流的分类

  • 按操作数据的单位不同,可以分为:字节流(8bit)、字符流(16bit)
  • 按数据流的流向不同,可以分为:输入流、输出流
  • 按流的角色不同,分为:节点流、处理流
抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer
  1. Java的IO流设计40多个类,实际上都非常规则。都是从上面的4个基本派生的
  2. 由这四个类派生出来的子类都是以其父类的名称作为子类的后缀

IO流体系

流的体系结构

抽象基类 节点流(文件流) 缓冲流(处理流的一种)
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream
Reader FileReader BufferedReader
Writer FileWriter BufferedWriter

FileReader 类读取文件

  • read() 方法的理解:返回读取到的一个字符,返回-1时表示读取完毕
  • 文件流必须手动调用 close 方法关闭,使用 try-catch-fianlly 包裹 FileReader 类的调用方法
  • 读取的文件必须存在,否则会报错
  • 提示:idea中选中一段代码,然后 CTRL+ALT+T 快速添加 try-catch 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.songzx.exer;

import org.junit.Test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-08 20:08
*/
public class Exer1 {
@Test
public void test1(){
// 1.指明文件地址,这个文件要真实存在
File file = new File("src\\hello.txt");
FileReader fr = null;
try {
// 2.使用try包裹FileReader类的实例
fr = new FileReader(file);
// 3.调用read方法,这个方法返回是一个int类型,当返回值等于-1时表示文件读取完毕
int data;
// 3.1 循环调用read方法,返回-1时截止
while ((data = fr.read()) != -1){
// 3.2 读取到要转成char类型
char s = (char) data;
System.out.print(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流,close方法仍然可能会有异常,所以也要用try-catch包裹
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

read(char[] cbuf) 一次读取多位字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.songzx.exer;

import org.junit.Test;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-08 20:46
*/
public class Exer2 {
@Test
public void test1() {
File file = new File("src\\hello.txt");
FileReader fr = null;
try {
fr = new FileReader(file);
// 定义一个char类型数组用来存放读到的字符,每次读取5个字符放到这个数组中
char[] cbuf = new char[5];
// 这里的len表示这次读到的字符个数
int len;
// read 方法传入一个 char 类型数组表示一次性读取多位字符
while ((len = fr.read(cbuf)) != -1){
// 错误写法
// for (int i = 0; i < cbuf.length; i++) {
// // 这样写当最后一次读取到的字符个数不足5时,会把之前读到的存放在数组中的数据一并输出
// System.out.print(cbuf[i]);
// }

// 正确写法,i 应该小于本次读取到字符长度
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

FileWrite 写入字符到文件中

  • 写入文件时如果文件不存在会自动创建
  • new FileWrite(File file,appent true) 实例化 FileWrite 类时第二个参数用来控制写入的文件是覆盖文件或者在原有文件基础上追加字符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.songzx.exer;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-09 19:32
*/
public class FileWriteTest{
public static void main(String[] args){
File file = new File("hello1.txt");
FileWriter fr = null;
try {
// 创建文件写入类的实例对象
// appent 用来控制是否覆盖原来的文件,或者在原来文件的基础上添加字符
fr = new FileWriter(file,true);

// 写入方法
fr.write("hello world\n");
fr.write("你好中国");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

复制一个文件内容到另外一个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.songzx.exer;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-09 19:44
*/
public class CopyFileTest {
public static void main(String[] args){
FileReader readerFr = null;
FileWriter writeFr = null;
try {
// 创建读取文件的对象
File file = new File("hello1.txt");
readerFr = new FileReader(file);

// 创建写入文件的对象
File file1 = new File("copyHello1.txt");
writeFr = new FileWriter(file1);

int data;
while ((data = readerFr.read()) != -1){
writeFr.write(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
readerFr.close();
writeFr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

复制一个图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.songzx.exer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-09 20:08
*/
public class CopyPng {
public static void main(String[] args) {
FileInputStream fr = null;
FileOutputStream fw = null;
try {
File file = new File("向日葵.png");
File file1 = new File("向日葵1.png");

fr = new FileInputStream(file);
fw = new FileOutputStream(file1);

int len;
// 字节文件要创建一个 byte 数组
byte[] bytes = new byte[5];
while ((len = fr.read(bytes)) != -1){
fw.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

复制文件方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.songzx.exer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* 复制一个文件公共方法
* @author songzhengxiang
* @create 2022-01-09 20:39
*/
public class CopyAvi {
public static void main(String[] args) {
String strpath = "D:\\开发工具包\\IllustratorCS6.zip";
String descpath = "D:\\开发工具包\\IllustratorCS6-copy.zip";

long start = System.currentTimeMillis();

CopyAvi.copyFileTest(strpath,descpath);

long end = System.currentTimeMillis();

System.out.println("复制耗时:" + (end - start)); //=> 6509
}
static void copyFileTest(String strPaht,String descPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File file = new File(strPaht);
File file1 = new File(descPath);

fis = new FileInputStream(file);
fos = new FileOutputStream(file1);

int len;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

使用缓冲流复制字节文件

  • 实例化缓冲流对象时需要传入节点流
  • 关闭流时要先关闭外面的缓冲流,再关闭里面的节点流
  • 关闭缓冲流的同时会关闭里面的节点流
  • 使用缓冲流读写文件的速度会得到提高,这是应为在其内部存在一个缓冲区
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.songzx.exer;

import java.io.*;

/**
* 使用缓冲流复制非文本文件(复制字节型文件)
* @author Songzx
* @date 2022/1/10
*/

public class BufferCopyByte {
public static void main(String[] args) {
String path1 = "D:\\工具\\navicat15破解版.zip";
String path2 = "D:\\工具\\navicat15破解版-copy2.zip";
try {
long start = System.currentTimeMillis();
BufferCopyByte.BufferCopyFile(path1,path2);
long end = System.currentTimeMillis();
System.out.println(end - start); //=> 185
} catch (IOException e) {
e.printStackTrace();
}
}
static void BufferCopyFile(String strpath,String descpath) throws IOException {
File file = new File(strpath);
File file1 = new File(descpath);

// 创建节点流
FileInputStream fir = new FileInputStream(file);
FileOutputStream fow = new FileOutputStream(file1);
// 创建处理流
BufferedInputStream bis = new BufferedInputStream(fir);
BufferedOutputStream bow = new BufferedOutputStream(fow);

int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1){
bow.write(bytes,0,len);
}
// 关闭外层的处理流的同时会关闭掉里面的节点流
bis.close();
bow.close();
}
}

使用缓冲流复制字符文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.songzx.exer;

import java.io.*;

public class BufferCopyChar {
public static void main(String[] args) {
String fromPath = "hello1.txt";
String descPath = "hello2.txt";
try {
BufferCopyChar.BufferCopy(fromPath,descPath);
} catch (IOException e) {
e.printStackTrace();
}
}
static void BufferCopy(String fromPath,String descPath) throws IOException {
File file = new File(fromPath);
File file1 = new File(descPath);

// 创建节点流
FileReader fr = new FileReader(file);
FileWriter fw = new FileWriter(file1);

// 创建处理流
BufferedReader bfr = new BufferedReader(fr);
BufferedWriter bfw = new BufferedWriter(fw);

int len;
char[] chars = new char[5];
while ((len = bfr.read(chars)) != -1){
bfw.write(chars,0,len);
}

// 关闭流
bfr.close();
bfw.close();
}
}

缓冲流都会有 flush 操作去刷新缓冲区。

统计文件中每个字符出现的次数并写入到新的文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.songzx.exer;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class GetTxtNumber {
public static void main(String[] args) {
try {
GetTxtNumber.getCount("hello1.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
static void getCount(String filePath) throws IOException {
// 1.获取文件对象
File file = new File(filePath);
// 2.创建流对象
FileReader fr = new FileReader(file);
BufferedReader bis = new BufferedReader(fr);
// 3.创建Map对象
HashMap<Character, Integer> map = new HashMap<>();

int key;
while ((key = bis.read()) != -1){
char mapKey = (char) key;
// 判断当前读取到的字符是否在map集合中存在,如果存在则数量加1
if(map.containsKey(mapKey)){
int befor = map.get(mapKey);
befor+=1;
map.put(mapKey,befor);
}else{
// 不存在则字符的数量默认是1
map.put(mapKey,1);
}
}

// 创建要写入的文件
File file1 = new File("helloCount.txt");
// 实例化写入流
FileWriter fileWriter = new FileWriter(file1,true);
// 遍历map中的Key和value
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
for (Map.Entry<Character, Integer> entry : entries) {
if(map.containsKey(entry.getKey())){
String row = entry.getKey() + ":" + entry.getValue();
// 将每个字符出现的次数写到新的文件中
fileWriter.write(row + "\n");
}
}

// 关闭流
bis.close();
fileWriter.close();
}
}

转换流概述

  • 两个转换流(都属于字符流)
    • InputStreamReader
    • OutputStreamWriter
  • 作用:将字节流和字符流之间相互转换

转换流的综合使用

将原本需要用字节读取的文件用字符来读取

下面代码的逻辑为:

hello2.txt –> 字节读取(byte)–> InputStreamReader 转换流 –> 字符读取(char

new FileOutputStream("hello3.txt"); –> 字节写入(bytes) –> OutputStreamWriter –> 字符写入(char

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.songzx.exer;

import java.io.*;

public class InputStarm {
public static void main(String[] args) throws IOException {
// 1.创建一个文件流,
FileInputStream fr = new FileInputStream("hello2.txt");
// 2.创建转换流,将读入字节流转换成读入字符流
// 这个类可以设置用什么类型去读取文件,默认是idea系统设置的类型,我们设置的是utf-8
// hello2.txt --> 字节流(byte) --> InputStreamReader -> 字符流(char)
InputStreamReader isr = new InputStreamReader(fr,"utf-8");

// 3.创建一个将字符转换为字节的写入流
FileOutputStream fos = new FileOutputStream("hello3.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);

int len;
char[] chars = new char[5];
// 将原本需要用字节读取的文件用字符来读取
while ((len = isr.read(chars)) != -1){
osw.write(chars,0,len);
}

osw.close();
isr.close();
}
}

数据流的写入和读取

  • DataOutputStream
  • DataInputStream
  • 只能写出基本数据类型
  • 在读取数据时要按照写入的顺序读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.songzx.exer;

import java.io.*;

public class DataInput {
public static void main(String[] args) throws IOException {
// 数据流的写出
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("zhangsan");
dos.flush();
dos.writeBoolean(true);
// 每次写出数据后要调用flush方法更新
dos.flush();

dos.close();

// 数据流的读出
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
// 在读取数据时要按照写入的顺序读取
String s = dis.readUTF();
boolean b = dis.readBoolean();
System.out.println(s); //=> zhangsan
System.out.println(b); //=> true

dis.close();
}
}

对象的序列化机制

  • 对象序列化允许把内存中的Java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久的保存再磁盘上,或者通过网络将这种二进制流传输到另外一个网络节点
  • 当其他程序获取到这种二进制流后可以恢复到原来的Java对象
  • 如果需要让某个对象支持序列化机制,则必须让对象的所属类及其属性是可序列化的。为了让某个类是可序列化的,必须让该类继承下面两个接口之一:
    • Serializable
      • 当实现 Serializable 接口时必须再类内部显示的声明 static final long serialVersionUID = 54564565L;
    • Externalizable
  • 类内部标记为 statictransient 的属性不能被序列化

对象流的写入和读取

  • ObjectOutputStream
  • ObjectInputStream
  • 除了可以写出基本数据类型之外,还可以写入Object 类型的数据
  • 在读取数据时可能会报 ClassNotFoundException 错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.songzx.exer;

import java.io.*;
import java.util.Date;

public class ObjectStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建对象数据写入流
FileOutputStream fos = new FileOutputStream("objectdata.dat");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(new Date());
oos.flush();
oos.writeInt(123);
oos.flush();

// 创建对象数据读取流
FileInputStream fis = new FileInputStream("objectdata.dat");
BufferedInputStream bis = new BufferedInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(bis);

// 在读取数据时要按照写入的顺序读取
Object o = ois.readObject();
int i = ois.readInt();
System.out.println(o);
System.out.println(i);

// 关闭流
oos.close();
ois.close();

}
}

自定义类的序列化和反序列化

首先定义一个自定义类,实现 Serializable 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.songzx.exer;

import java.io.Serializable;

public class Person implements Serializable {
// 继承Serializable类之后要定义一个long类型的serialVersionUID
static final long serialVersionUID = 54564565L;
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

实现自定义类的序列化和反序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.songzx.exer;

import java.io.*;

public class ObjectStream2 {
public static void main(String[] args) {
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
// 序列化
oos = new ObjectOutputStream(new FileOutputStream("Person.data"));
oos.writeObject(new Person("张三",15));
oos.flush();

// 反序列化
ois = new ObjectInputStream(new FileInputStream("Person.data"));
try {
Object o = ois.readObject();
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

随机读取文件类

  • RandomAccessFile
  • 创建一个 RandomAccessFile 时可以指定两种模式
    • rw:可读可写
    • r:只读
    • w:只写
  • 每次读写数据后指针自动往后移动一位
  • 一位表示一个字节
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.songzx.exer;

import java.io.IOException;
import java.io.RandomAccessFile;

public class ReadomAccessTest {
public static void main(String[] args) throws IOException {
// 创建随机读取文件类,文件不存在时自动创建
// rw:可读可写;r:只读;w:只写
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
// 将文件的长度设置为0,表示清空文件数据
raf.setLength(0);

// 往文件中添加数据
raf.writeByte(1);
raf.writeByte(2);
raf.writeByte(3);
raf.writeByte(4);

// 将指针移动到2的位置
raf.seek(2);
// 替换指针为2的位置的值为22,之后指针后移
raf.writeByte(22);
// 由于现在指针指向下标3,所以读取的值为4(下标从0开始)
System.out.println(raf.readByte()); // 4
// 重新将指针移动到起始点开始遍历,每次读写数据后指针会往后移动一位
raf.seek(0);
for (int i = 0; i < raf.length(); i++) {
System.out.println(raf.readByte());
}
}
}

RandomAccessFile 实现数据插入

  • 字符串调用 getBytes() 方法将字符转换成字节
  • 使用 list 保存文件中的数据然后遍历重新读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.songzx.exer;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;

public class RandomAccessTest2 {
/**
* 实现数据插入效果
* @author Songzx
* @date 2022/1/11
*/

public static void main(String[] args) throws IOException {
// 字符串调用 getBytes() 方法将字符转换成字节
RandomAccessTest2.setIndex(2,"123".getBytes());
}

static void setIndex(int index,byte[] bs){
RandomAccessFile raf = null;
try {
// 声明一个随机读取文件流
raf = new RandomAccessFile("random.data", "rw");
// 首先将指针移动到要插入的位置
raf.seek(index);
byte[] bytes = new byte[1024];
int len;
// 借助list用来存储当前指针后面的数据
ArrayList<Byte> oldlist = new ArrayList<>();
while ((len = raf.read(bytes)) != -1){
for (int i = 0; i < len; i++) {
oldlist.add(bytes[i]);
}
}
// 拿到要插入的位置的后面的数据后,再将指针移动到要插入的位置
raf.seek(index);
// 插入新增的数据
raf.write(bs);
// 再将旧数据追加到新增数据后面
for (Byte aByte : oldlist) {
raf.writeByte(aByte);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

使用第三方包复制文件

这里我们用到了操作文件的第三方包 org.apache.commons.io.FileUtils

官方网站:https://commons.apache.org/proper/commons-io/

首先我们选择版本下载

点击 download 进入具体的下载页面,然后选择 zip 格式的文件进行下载

下载后解压复制 commons-io-2.11.0.jar 文件

然后回到IDEA中,在我们的工程下右键新建 Directory

输入名称 libs,然后将我们复制的 jar 文件粘贴到该处并点击OK

然后在这个包上右键选择 Add as Library 将依赖包应用到项目中

点击后在弹出的框中点击ok

然后再代码中就可以用这个包提供的相关方法了

下面的代码将使用这个包提供的复制方法复制一个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.songzx.io;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/**
* @author songzhengxiang
* @create 2022-01-11 20:59
*/
public class UtilsFilsTest {
public static void main(String[] args) {
File srcFile = new File("向日葵.png");
File descFile = new File("向日葵2.png");

try {
// 使用工具类复制文件
FileUtils.copyFile(srcFile,descFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}

编程练习题

创建文本文件并追加数据

实现往一个文本文件中追加100个随机生成的整数,如果文件不存在则创建该文件。整数用空格分隔,文件名:Exer01.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.songzx.test;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Exer1 {
/**
* 实现往一个文件中追加100个随机生成的整数,如果文件不存在则创建该文件
* 整数用空格分隔,文件名:Exer01.txt
*
* @author Songzx
* @date 2022/1/11
*/

public static void main(String[] args) throws IOException {
// 创建写文件流,模式为追加
FileWriter fw = new FileWriter("Exer01.txt",true);
for (int i = 0; i < 100; i++) {
int v = (int) (Math.random() * 100 + 1);
fw.write(v + "\t");
}
fw.close();
}
}

创建字节文件并追加数据

实现往一个字节文件中追加100个随机生成的整数,如果文件不存在则创建该文件。整数用空格分隔,文件名:Exer02.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.songzx.test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Exer2 {
/**
* 创建一个字节文件,实现往里面追加100个随机的整数并读取
* 如果文件不存在则自动创建
*
* @author Songzx
* @date 2022/1/11
*/

public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("Exer02.data");
for (int i = 0; i < 100; i++) {
int v = (int) (Math.random() * 100) + 1;
fos.write(v);
}
fos.close();

FileInputStream fis = new FileInputStream("Exer02.data");
int len;
byte[] bytes = new byte[5];
while ((len = fis.read(bytes))!=-1){
for (int i = 0; i < len; i++) {
System.out.println(bytes[i] + "===>" + i);
}
}

fis.close();
}
}

对字节文件中的所有整数进行求和

这道题默认你已经完成了第二道题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.songzx.test;

import java.io.FileInputStream;
import java.io.IOException;

public class Exer3 {
public static void main(String[] args) throws IOException {
// 创建文件流
FileInputStream fis = new FileInputStream("Exer02.data");
int len;
int count = 0;
byte[] bytes = new byte[5];

// 总数累加过程
while((len = fis.read(bytes)) != -1){
for (int i = 0; i < len; i++) {
count += bytes[i];
}
}
System.out.println(count);

// 关闭流
fis.close();
}
}

将文本文件转换为UTF

读取一个文本文件,并将这个文件的数据以utf-8的格式写入一个字节文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.songzx.test;

import java.io.*;

public class Exer4 {
/**
* 读取一个文本文件,并将这个文件的数据以utf-8的格式写入一个字节文件中
* @author Songzx
* @date
*/

public static void main(String[] args) throws IOException {
// 创建一个文件读取的转换流
InputStreamReader isr = new InputStreamReader(new FileInputStream("hello2.txt"),"utf-8");
// 创建一个文件写入的转换流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Exer03.dat"),"utf-8");
// 文件写入过程
int len;
char[] chars = new char[5];
while ((len = isr.read(chars)) != -1){
osw.write(chars,0,len);
}
// 关闭流
isr.close();
osw.close();
}
}

将对象和数组保存在文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.songzx.test;

import java.io.*;
import java.util.Date;

public class Exer5 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建写入对象类
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Exer05.txt"));
int[] ints = {1, 2, 3, 4, 5};
Date date = new Date();
double d = 55.55;
// 写入过程
oos.writeObject(ints);
oos.writeObject(date);
oos.writeDouble(d);
// 关闭写入流
oos.close();

// 创建读取对象文件流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Exer05.txt"));
// 按照写入的顺序读取
Object o = ois.readObject();
Object o1 = ois.readObject();
double v = ois.readDouble();

System.out.println(o);
System.out.println(o1);
System.out.println(v);
// 关闭流
ois.close();

}
}

使用 RandomAccessFile 切割文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.songzx.test;

import java.io.*;

public class SplitPng {
public static void main(String[] args) {
// 切割图片
SplitPng.splitPngFun();
// 合并图片
SplitPng.mergePng();
}

// 将一个图片切成三个图片
static void splitPngFun(){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("向日葵.png", "rw");
try {
System.out.println(raf.length());
raf.seek(0);
FileOutputStream fis = new FileOutputStream("图片1.png",true);
FileOutputStream fis2 = new FileOutputStream("图片2.png",true);
FileOutputStream fis3 = new FileOutputStream("图片3.png",true);

while ((raf.getFilePointer() < raf.length())){
long nowPoint = raf.getFilePointer();
System.out.println(nowPoint);
if(nowPoint >=0 && nowPoint <= 200000){
fis.write(raf.readByte());
}
if(nowPoint >200000 && nowPoint <= 400000){
fis2.write(raf.readByte());
}
if(nowPoint >400000 && nowPoint < raf.length()){
fis3.write(raf.readByte());
}
}
} catch (IOException e) {
e.printStackTrace();
}


} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

// 将三个图片合并为一个图片
static void mergePng() {
FileInputStream fis1 = null;
FileInputStream fis2 = null;
FileInputStream fis3 = null;
FileOutputStream fos = null;
try {
fis1 = new FileInputStream("图片1.png");
fis2 = new FileInputStream("图片2.png");
fis3 = new FileInputStream("图片3.png");
fos = new FileOutputStream("合成.png", true);

int len;
byte[] bytes = new byte[1024];

// 写入第一个
while ((len = fis1.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 写入第一个
while ((len = fis2.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 写入第一个
while ((len = fis3.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis1.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis2.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis3.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}