欢迎来到我的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

能懂系列之 Java.IO 字节流读写文件

  |   0 评论   |   0 浏览

工作开发中,对文件的操作肯定是少不了的,所以搞懂文件操作的基础 IO 流是相当有必要的,所以今天阿淼就给大家普及一下。

一、Java文件读写操作的分类

首先,阿淼给大家绘制了一张 IO 流的关系图:

IO流.jpg

看完过后有没有一目了然的感觉?有的话就对了,赶紧保存下来吧。

从图中么我们可以清晰的看到:java 将文件的读写分成了字节流和字符流,字节流主要是对非文本文件的操作,读和写操作的单位都是字节;字符流主要是对文本文件的操作,读和写操作的基本单位都是一个字符而不仅仅是单个字节。

在每种流种都有写操作和读操作,即输出流,输入流。

二、编码表的简单介绍

计算机都只记录‘0’和‘1’,要形成我们所见到的万千气象,则需要将数据中的‘0’、‘1’与编码表对照。

正所谓 “道生一,一生二,二生三,三生万物”

对于中文的读写,单纯用字节流将会出现乱码的现象,因为在编码表中,一个中文字符不仅仅是占一个字节大小。造成这个现象主要是因为编码表不同而造成的。

常用的英文编码表为ASCII,这个编码表每个符号都只占用一个字节总共有256个内容,但是因为这个编码表的表示很有局限性,并不能表示其他文字。

对于中文而言,使用最多的就是GBK和UTF-8两种编码表

在互联网中,最的普遍使用的还是UTF-8编码表。
这两种编码表为了和ASCII表保持兼容性,都将前面256个保持和ASCII表相同,使用2字节(GBK),3字节(UTF-8)表示一个字符。

三、字节流操作。

1.字节输出流OutputStream

OutputStream是一个抽象类,表示输出字节流的所有类的父类。输出流接受输出字节并将这些字节发送到某个接收器。

需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。
而在此抽象方法中,定义了输出字节流的基本方法。

void close()
    //关闭此输出流并释放与此流有关的所有系统资源。
void flush()
    //刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
    //将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
    //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
void write(int b)
    //将指定的字节写入此输出流。

在OutputStream类中,有一个已经实现的类,FileOutputStream类,用于数据写入到文件中。

①FileOutputStream

FileOutputStream,文件输出流,功能是将数据输出到FileOutputStream所指定的对象中。

FileOutputStream构造方法摘要:

/*文件覆盖写入构造*/
FileOutputStream(File file)
    //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String pathname)
    //创建一个向具有指定名称的文件中写入数据的输出文件流。
  
/*文件续写构造*/
FileOutputStream(File file, boolean append)
    //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String pathname, boolean append)
    //创建一个向具有指定 name 的文件中写入数据的输出文件流。

既然FileOutputStream是OutputStream的一个继承类,那么就可以直接使用OutputStream中定义好的方法来写入数据了。

FileOutputStream覆盖写入数据代码演示:

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

public class FileOutputStreamDemo {
	public static void main(String[] args) throws IOException{
		//在D:\JavaStudyCode中创建存储数据的文件OutputStream.txt
		File f = new File("D:\\JavaStudyCode\\OutputStreamDemo.txt");

		//单参数构造方法,创建一个文件输出流对象,指定数据输出存储的位置
		FileOutputStream fos = new FileOutputStream(f);
		//通过FileOutputStream指定的文件不存在会被创建,如果存在则会被覆盖

		//调用FileOutputStream父类OutputStream的方法进行数据写入
		fos.write(65);	//write(int b)方法写入一个字节数据

		/*
		*fos.write(65)会将65这个字节数据对照编码表进行写入,
		*所以文件出现的内容是一个字母‘A’
		*/

		byte[] bytes = {65,66,67};
		fos.write(bytes);	//write(byte[] b)方法写入一个字节数组数据

		/*
		*fos.write(bytes)会将字节数组中的三个数据,65,66,67
		*对照编码表进行写入
		*被写入的内容为‘A’‘B’‘C’三个字母
		*加上上一句写入的‘A’
		*此时文件内容为AABC
		*/

		//write(bytes,1,1)方法写入从bytes数组索引1开始的2个字节数据
		fos.write(bytes,1,2);   

		/*
		*fos.write(bytes,1,2)会将bytes数组索引1开始的2个字节数据
		*对照编码表进行写入
		*所以写入的内容为‘B’‘C’
		*加上前面的内容,文件中的内容为AABCBC
		*/

		//关闭流并且释放占用资源
		fos.close();
	}
}

FileOutputStream续写数据代码演示:

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

public class WritennAndNewLine {
	public static void main(String[] args) throws IOException{
		//在D:\JavaStudyCode中创建存储数据的文件OutputStream.txt
		File f = new File("D:\\JavaStudyCode\\OutputStreamDemo.txt");
		
		//创建一个文件输出流对象,指定数据输出存储的位置
		FileOutputStream fos = new FileOutputStream(f,true);
		//双参数构造方法,第二个参数为true时不会覆盖原来的文件,而是进行续写

		fos.write(68);//在前面的操作写在文件中的内容之后写入一个D
		/*
		 * 文件中的内容为AABCBC加上这个方法写入的D为AABCBCD
		 */


		//写入数据的换行操作
		String str = "\r\n"+"换行后的字符";
		//调用String的getBytes()方法,将String转成byte数组写入
		fos.write(str.getBytes());  

		fos.close();
	}
}

此时文件中的内容为:

AABCBCD
换行后的字符

\r   \n为转移字符; \后面跟着字符将字母转成了特定用途的标识符
\r回车符   \n换行符;   在文本写入时有相同的换行作用

2.字节输入流InputStream

InputStream也是一个抽象类,与OutputStream为一个同等的相对作用的类,将文件中的内容读入到内存中,表示字节输入流的所有类的父类。
需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。
而在此抽象方法中,定义了输入字节流的基本方法。

void close() 
    关闭此输入流并释放与该流关联的所有系统资源。 
int read() 
    从输入流中读取数据的下一个字节,如果没有字节返回-1
int read(byte[] b) 
    从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中,返回读取到的字节数
int read(byte[] b, int off, int len) 
    将输入流中最多 len 个数据字节读入 byte 数组。

在InputStream类中,有一个已经实现的类,FileInputStream类,用于将文件中的数组读入内存中程序使用。

①FileInputStream

FileInputStream,文件输入流,功能是将FileInputStream所指定的对象文件中的数据读入到内存中。
FileInputStream构造方法摘要:

FileInputStream(String name) 
    //通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
FileInputStream(File file) 
    //通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。

同样的,FileInputStream是InputStream的一个继承类,那么就可以直接使用InputStream中定义好的方法d读取数据了。

FileInputStream读取文件数据到内存:

代码演示:

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

public class InputStreamDemo {
	public static void main(String[] args) throws IOException {
	    //使用原先写入好的并删除掉中文字符后的数据文件OutputStream.txt,
		//创建File对象
		File f = new File("D:\\JavaStudyCode\\OutputStreamDemo.txt");
		
		//创建一个文件输入流对象,指定数据读取的文件的位置
		FileInputStream fis = new FileInputStream(f);

		//一次读取一个字节
		int data = 0;	//	记录read方法的返回值,不是-1则循环读取
		while((data = fis.read()) != -1) {
			System.out.println("initial is "+data);
			System.out.println("changed is "+(char)data);
		}

		fis.close();
	}
}

结果输出:

initial is 65
changed is A
initial is 65
changed is A
initial is 66
changed is B
initial is 67
changed is C
initial is 66
changed is B
initial is 67
changed is C
initial is 68
changed is D
initial is 68
changed is D
initial is 13
changed is 

initial is 10
changed is

对于这种一次读取一个字节的方法是极度低效的,如果一个文件稍微大一点的话,就能够明显感觉到读取很慢,所以可以采用read()的一个重载方法,先将内容读取到一个中间容器byte数组中。

FileInputStream读取多字节数据到内存:

代码演示:

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

public class InputStreamDemo {
	public static void main(String[] args) throws IOException {
		//在D:\JavaStudyCode中创建存储数据的文件OutputStream.txt
		//创建File对象
		File f = new File("D:\\JavaStudyCode\\OutputStreamDemo.txt");
		
		//创建一个文件输入流对象,指定数据读取的文件的位置
		FileInputStream fis = new FileInputStream(f);

		//一次读取一个bytes数组大小的字节,长度可以是1024的整数倍
		byte[] bytes= new byte[1024];
		int length = 0;	//	记录read方法的返回值,不是-1则循环读取
		while((length = fis.read(bytes)) != -1) {
			System.out.println(new String(bytes,0,length));
		}

		fis.close();
	}
}

输出结果是:

AABCBCDD

标题:能懂系列之 Java.IO 字节流读写文件
作者:spirit223
地址:https://www.mmzsblog.cn/articles/2020/08/01/1596253370864.html
-----------------------------
如未加特殊说明,此网站文章均为原创。
转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。

个人微信公众号 ↓↓↓                 

微信搜一搜 Java 学习之道