字符流 FileReader、FileWriter 解析

  • 字符流:顾名思义读取的是字符
  • 常用于处理文本文件

1. FileReader

  • 读取方法 read( )
int read()
//读取单个字符。将读取的字符转换成整数并返回(范围在 0 到 65535 之间),如果已到达流的末尾则返回 -1

int read(char[] cbuf) //将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数

int read(char[] cbuf,int off,int len) //将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字符。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数

对读取方法read( )的说明:每次读取1个字符,并不一定每次都读取2Byte,与编码方式有关。比如文件中有内容 “Hello世界” 。
若采用GBK编码,则 " Hello “共读取5次,每次读取1Byte,” 世界 “共读取2次,每次读取2Byte。
若采用UTF-8编码,则” Hello “共读取5次,每次读取1Byte,” 世界 "共读取2次,每次读取3Byte。
相关编码方式请点击此处查看
char字符解析请点击此处查看

  • 代码示例
    " HelloWorld.txt " 文件内容如下 ( 采用UTF-8编码 )
//调用read()方法
File file = new File("HelloWorld.txt"); // 1.创建File对象
FileReader fr = null;
try
{
    
    
	fr = new FileReader(file); // 2.实例化FileReader
	int data;
	while ((data = fr.read()) != -1) // 3.调用read()方法
			System.out.print((char) data);
} catch (FileNotFoundException e)
{
    
    
	e.printStackTrace();
} catch (IOException e)
{
    
    
	e.printStackTrace();
} finally
{
    
    
	try
	{
    
    
		if (fr != null) // 此处判断的目的是防止2处实例化FileReader失败导致对象引用为空
			fr.close(); // 4.关闭资源
	} catch (IOException e)
	{
    
    
		e.printStackTrace();
	}
}
//Hello  World!!!   你好 世界!!!
//Hello  World!!!   你好 世界!!!

Q:char 底层是2Byte,为何能将读取的3Byte正确解码
A:char本质上是一个固定占用两个字节的无符号正整数( 0-65535 ),正整数对应于Unicode编号。文件中的中文对应的Unicode值在0-65535之间,所以可以正确解码。

// 调用read(char []) 方法
File file = new File("HelloWorld.txt"); // 1.创建File对象
FileReader fr = null;
try
{
    
    
	fr = new FileReader(file); // 2.实例化FileReader
	char[]cbuf=new char[5];	//每次读取5个字符	
	int len; //len保存每次实际在cbuf数组中装载的字符(若装满5个则len=5,没装满则返回实际装载的大小)
	while ((len = fr.read(cbuf)) != -1) // 3.调用read()方法
	{
    
    
		for(int i=0;i<len;i++)
			System.out.print(cbuf[i]);
	}
} catch (FileNotFoundException e)
{
    
    
	e.printStackTrace();
} catch (IOException e)
{
    
    
	e.printStackTrace();
} finally
{
    
    
	try
	{
    
    
		if (fr != null) // 此处判断的目的是防止2处实例化FileReader失败导致对象引用为空
			fr.close(); // 4.关闭资源
	} catch (IOException e)
	{
    
    
		e.printStackTrace();
	}
}
//Hello  World!!!   你好 世界!!!
//Hello  World!!!   你好 世界!!!
1.read(char[])方法的错误写法1(仅对上述代码修改部分)

while ((len = fr.read(cbuf)) != -1) // 3.调用read()方法
{
    
    
	for(int i=0;i<cbuf.length;i++)//对i的循环条件进行更改
		System.out.print(cbuf[i]);
}
//Hello  World!!!   你好 世界!!!
//Hello  World!!!   你好 世界!!!世
不难发现末尾多输出 "世" 。原因如下:文件中共有字符54(英文字母20个,中文字母8个,感叹号12个,空格12个,换行符2)
循环条件是i<cbuf.length即 i < 5
所以共进入while语句11(添加相应的计数变量发现确实如此)10次在cbuf数组中装载的5个字符是 空格你好空格世
第11次只剩下4个字符 界!!! 第10次装载的第5个字符"世"没有被覆盖,所以最后多显示了"世"

2.read(char[])方法的错误写法2(原因同上)
while ((len = fr.read(cbuf)) != -1)
      String str = new String(cbuf);

3.read(char[])方法的正确写法2
while ((len = fr.read(cbuf)) != -1)
      String str = new String(cbuf,0,len);

2. FileWriter

  • 写入方法 write( )
void write(String str)
void write(String str, int off, int len)
void write(char cbuf[])
void write(char cbuf[], int off, int len)
  • 构造器
public FileWriter(File file)// 相当于调用第二个构造器,只不过boolen append=false(默认值)
public FileWriter(File file, boolean append)
public FileWriter(String fileName, boolean append)
  • 代码示例
//HelloWorld1.txt在跑程序前没有被创建
public void test() throws IOException
{
    
    
	File file = new File("HelloWorld1.txt"); // 1.创建File对象
	FileWriter fw = new FileWriter(file); // 2.创建FileWriter对象
	fw.write("Java Language");// 3.调用方法
	fw.close(); // 4.关闭资源
}
运行后发现在对应的文件夹下自动创建了"HelloWorld1.txt"文件并将"Java Language"成功写入文件
//HelloWorld1.txt在跑程序前已经被创建,含有内容"Java Language"
public void test() throws IOException
{
    
    
	File file = new File("HelloWorld1.txt"); // 1.创建File对象
	FileWriter fw = new FileWriter(file); // 2.创建FileWriter对象
	fw.write("Java Language Is Good");// 3.调用方法
	fw.close(); // 4.关闭资源
}
运行后发现已经将"Java Language Is Good"成功写入文件并且只有"Java Language Is Good"
说明后来写入的新数据覆盖了原来的旧数据,结合对应的构造器不难理解其中原理
//HelloWorld1.txt在跑程序前已经被创建,含有内容"Java Language Is Good"
public void test() throws IOException
{
    
    
	File file = new File("HelloWorld1.txt"); // 1.创建File对象
	FileWriter fw = new FileWriter(file,true); // 2.创建FileWriter对象,允许在末尾添加
	fw.write("Java Language Is Good");// 3.调用方法
	fw.close(); // 4.关闭资源
}
运行后发现已经将"Java Language Is Good"成功写入文件并且有2"Java Language Is Good"
说明后来写入的新数据添加在旧数据的末尾,结合对应的构造器不难理解其中原理
  • File对应的文件如果在硬盘中不存在,则会自动创建此文件。
  • 使用流的构造器:FileWriter(file,false) / FileWriter(file) 会对原有文件的覆盖
  • 使用流的构造器:FileWriter(file,true) 会在原有文件基础上追加内容

3. 通过FileReader、FileWriter实现文本的复制

public void test5() throws IOException
{
    
    
		File srcFile=new File("SrcTest.txt");
		File destFile=new File("DestTest.txt");
		
		FileReader fileReader = new FileReader(srcFile);
		FileWriter fileWriter = new FileWriter(destFile,true);
		
		int data;
		while((data=fileReader.read())!=-1)
			fileWriter.write(data);
		
		fileReader.close();
		fileWriter.close();
}

成功实现了文本的复制

猜你喜欢

转载自blog.csdn.net/weixin_43956248/article/details/113879233