0%

Java 文件基本技术(二):二进制文件和字节流

1. InputStream 中常见的方法有哪些

  • 基本方法

    1
    2
    3
    4
    public abstract int read() throws IOException;
    public int read(byte[] b) throws IOException;
    public int read(byte b[], int off, int len) throws IOException;
    public void close() throws IOException; //流读取结束后,关闭,释放相关资源
  • 高级方法

    1
    2
    3
    4
    5
    public long skip() throws IOException;
    public int available() throws IOException;
    public synchronized void mark(int readlimit);
    public boolean markSupported();
    public synchronized void reset() throws IOException;

2. OutputStream 中常见方法有哪些

1
2
3
4
5
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException;
public void write(byte b[], int off, int len) throws IOException;
public void flush() throws IOException; //将缓冲而未实际写入的数据进行实际写入
public void close() throws IOException; //一般会先调用 flush() 方法,然后再释放流占用的系统资源

3. 将字符串 “hello, 123, 老隋” 写到文件 hello.txt 中

1
2
3
4
5
6
7
8
OutputStream output = new FileOutputStream("hello.txt");
try {
String data = "hello, 123, 老隋";
byte[] bytes = data.getBytes(Charset.forName("UTF-8"));
output.write(bytes);
} finally {
output.close();
}

4. 接上题,将上面写入的文件 “hello.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
36
37
38
39
40
41
42
43
InputStream input = new FileInputStream("hello.txt");
try {
//方式一:假定一次 read 调用就读到了所有内容,且假定字节长度不超过 1024
byte[] buf = new byte[1024];
int bytesRead = input.read(buf);

//方式二:为了确保读到所有内容,可以逐个字节读取直到文件结束
int b = -1;
int bytesRead = 0;
while((b=input.read()) != -1) {
buf[bytesRead++] = (byte)b;
}

//方式三:在没有缓冲的情况下逐个字节读取性能很低,可以使用批量读入且确保读到结尾。
//不过,这还是假定文件内容长度不超过一个固定的数字 1024。如果不确定文件内容的长度,但不希望一次性分配过大的 byte 数组,又希望将文件内容全部读入,可以借助 ByteArrayOutputStream
byte[] buf = new byte[1024];
int off = 0;
int bytesRead = 0;
while((bytesRead = input.read(buf, off, 1024-off)) != -1) {
off += bytesRead;
}
String data = new String(buf, 0, off, "UTF-8");

//方式四:使用 ByteArrayOutputStream,改进上面读写文件代码,确保将所有文件内容读入
InputStream input = new FileInputStream("hello.txt);
try {
ByteArrayOutputStream output = new ByteArrayOutputSteam();
byte[] buf = new byte[1024];
int bytesRead = 0;
while((bytesRead = input.read(buf)) != -1) {
output.write(buf, 0, bytesRead);
}
String data = output.toString("UTF-8);
System.out.println(data);
} finally {
input.close();
}

String data = new String(buf, 0, bytesRead, "UTF-8");
System.out.println(data);
} finally {
input.close();
}

5. 保存一个学生列表到文件中

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
//学生类
class Student {
String name;
int age;
double score;
//省略构造方法和 getter/setter 方法
}

//学生列表内容
List<Student> students = Arrays.asList(new Student[] {new Student("张三", 18, 80.9d), new Student("李四", 17, 67.5d)});

//将该列表内容写到文件 students.dat 中
public static void writeStudents(List<Student> students) throws IOException {
DataOutputStream output = new DataOutputStream(new FileOutputSteam("students.dat));
try {
output.writeInt(students.size());
for(Student s : students) {
output.writeUTF(s.getName());
output.writeInt(s.getAge());
output.writeDouble(s.getScore());
}
} finally {
output.close();
}
}

6. 接上题,从文件中读进内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static List<Student> readStudents() throws IOException {
DataInputStream input = new DataInputStream(new FileInputStream("students.dat"));
try {
int size = input.readInt();
List<Student> students = new ArrayList<Student> (size);
for(int i=0; i<size; i++) {
Student s = new Student();
s.setName(input.readUTF());
s.setAge(input.readInt());
s.setScore(input.readDouble());
student.add(s);
}
return students;
} finallly {
input.close();
}
}
  • 分析:使用 DataInputStream/DataOutputStream 读写对象,非常灵活,但比较麻烦,所以 Java 提供了序列化机制

7. 复制输入流的内容到输出流

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
public static void copy(InputStream input, OutputStream output) throws IOException {
byte[] buf = new byte[1024];
int bytesRead = 0;
while((bytesRead = input.read(buf)) != -1) {
output.write(buf, 0, bytesRead);
}
}

//实际上,在 Java 9 中,InputStream 类增加了一个方法 transferTo(),可以实现相同的功能,实现是类似的
public long transferTo(OutputStream out) throws IOException {
Object.requireNonNull(out, "out");
long transferred = 0;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; // buf 大小是 8192
int read;
while((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
out.write(buffer, 0, read);
transferred += read;
}
return transferred;
}

//将文件读入字节数组
public static byte[] readFileToByteArray(String fileName) throws IOException {
InputStream input = new FileInputStream(fileName);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
copy(intpu, output);
return output.toByteArray();
} finally {
input.close();
}
}

//将字节数组写到文件
public static void writeByteArrayToFile(String fileName, byte[] data) throws IOException {
OutputStream output = new FileOutputStream(fileName);
try {
output.write(data);
} finally {
output.close();
}
}
-------------------- 本文结束感谢您的阅读 --------------------