【Java文件流】为什么要诞生“字符流”,字节流不是更胜任二进制数据的处理吗?

根本原因是由于人和机器的差距:机器擅长处理二进制的机器码,而人只能处理特殊的字符(如"a",“你好”)。于是,采用字符流来作为人能读的文件机器能读的文件之间的转换桥梁。

诞生背景:

  • 字节流对所有的文件操作都是按照一个个二进制位的形式;
  • 然而,字节流在操作字符时,可能会有中文导致的乱码,所以由字节流引申出了字符流。

为什么要诞生字符流:

  • 机器擅长处理二进制的机器码,而人只能处理特殊的字符(如"a",“你好”)。
  • 于是,采用字符流来作为人能读的文件机器能读的文件之间的转换桥梁。

字符流的功能:

  1. 把读取到的二进制数据进行对应的编码和解码工作;从而把二进制位转换成程序员期待的字符集。
  2. 字符流=字节流+编码(解码);

字符流的弊端:

  • 一:无法拷贝图片和视频。
  • 二:拷贝文件使用字节流而不使用字符流,因为字符流读文件涉及到解码,会先解码,写文件的时候又涉及到编码,这些操作多余,而且读和写的码表不对应还容易引发问题。
  • 例如FileReader 读文件,我们没有指定编码时,默认是按照系统编码gbk进行操作,如果读到utf-8的文件也是按照gbk编码进行解码,那就会出现问题。

字符流体系结构

输入字符流:
---------| Reader 所有输入字符流的基类。 抽象类。
----------------| FileReader 读取文件数据的输入字符流。
----------------|BufferedReader 缓冲输入字符流。该类出现的目的是为了提高读取文件数据的效率与拓展FileReader的(readLine)功能。这个类的也只不过是在内部维护了一个8kb的字符数组而已。

输出字符流:
---------| Writer 所有输出字符流的基类。 抽象类
----------------| FileWriter 向文件输出数据的输出字符流
----------------| BufferedWriter 缓冲输出字符流。该类出现的目的是为了提高写文件数据的效率与拓展FileWriter的(newLine)功能。

FileReader

在这里插入图片描述

FileReader类操作步骤、方法与FileInputStream类相同;缓冲流的使用方法与FileInputStream类相同,即bufferedReader包装FileReader

读取方法:
1,int read()一次读取一个字符。返回的是读到的那个字符的int值。如果读到流的末尾,返回-1.
2,int read(char[]):将
读到的字符存入指定的数组中
,返回的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1.

快速理解FileReader的用法:

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

public class Main {
	public static void main(String[] args) throws IOException {
		readOneCharacter(); //读取一个字符
		readCharacterArray(); //读取一个字符数组
	}

	public static void readOneCharacter() throws IOException {
		FileReader fr = new FileReader("c:\\users\\kyles\\desktop\\a.txt");
		int ch;
		while((ch=fr.read())!=-1) {
			System.out.print((char)ch);
		}
		fr.close();
	}
	public static void readCharacterArray() throws IOException {
		FileReader fr = new FileReader("c:\\users\\kyles\\desktop\\a.txt");
		char[] chs = new char[1024]; //这里可以是1024及其整数倍
		int len;
		while((len=fr.read(chs))!=-1) {
			System.out.print(new String(chs,0,len));
		}
		fr.close();
	}
}

FileWriter

在这里插入图片描述

使用FileWriter写数据的时候

  1. FileWriter内部是维护了一个1024个字符数组的,写数据的时候会先写入到它内部维护的字符数组中,如果需要把数据真正写到硬盘上,需要调用flush或者是close方法或者是填满了内部的字符数组
  2. 如果目标文件不存在,那么会自动创建目标文件。
  3. 如果目标文件已经存在了,那么默认情况会先清空文件中的数据,然后再写入数据。

向磁盘文件写数据的五种方法:(五种write方法的重载)

public void write(int c) throws IOException  写入的字符包含在给定整数值的16个低位中; 忽略16个高位。
public void write(char[] cbuf) throws IOException
public abstract void write(char[] cbuf, int off, int len) throws IOException
public void write(String str) throws IOException
public void write(String str, int off, int len) throws IOException

向一个文件中写入一个字符串

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

public class Main {
	public static void main(String[] args) throws IOException { //为了快速理解,异常直接向函数外抛
		FileWriter fw = new FileWriter("C:\\users\\kyles\\desktop\\a.txt");
		fw.write("IO流你好"); //数据没有直接写到文件,其实是写到了内存缓冲区
		
		fw.flush(); //把缓冲区的数据写入到文件
		fw.close(); //先刷新缓冲区,然后通知系统释放资源。
	}
}

五种write方法示例

import java.io.FileWriter;
import java.io.IOException;
public class Main {
	public static void main(String[] args) throws IOException {
		//创建输出流对象
		FileWriter fw = new FileWriter("b.txt");
		
		//void write(String str):写一个字符串数据
		fw.write("abcde");
		
		//void write(String str,int index,int len):写一个字符串中的一部分数据
		fw.write("abcde",0,5);
		fw.write("abcde",1,3);
		
		//void write(int ch):写一个字符数据,这里写int类型的好处是既可以写char类型的数据,也可以写char对应的int类型的值。'a',97
		fw.write('a');
		fw.write(97);
		
		//void write(char[] chs):写一个字符数组数据
		char[] chs = {'a','b','c','d','e'};
		fw.write(chs);
		
		//void write(char[] chs,int index,int len):写一个字符数组的一部分数据
		fw.write(chs,0,5);
		fw.write(chs,2,3);
		
		//释放资源
		fw.close();
	}
}

文件追加

  • 在构造函数时就设置为追加模式:
FileWriter(String fileName, boolean append) 
FileWriter fw = new FileWriter("c.txt",true); //表示追加写入,默认是false
FileWriter(File file, boolean append)
  • 使用append方法
Writer append(char c); //将制定字符添加到此Writer
Writer append(CharSequence csq); //将制定字符序列添加到此Writer
Writer append(CharSequence csq, int start, int end);

示例:

import java.io.FileWriter;
import java.io.IOException;
public class Main {
	public static void main(String[] args) throws IOException {
		FileWriter fw = new FileWriter("c:\\users\\kyles\\desktop\\a.txt");
		for(int x=0; x<10; x++) {
			fw.write("hello"+x);
			fw.write("\r\n");
		}
		fw.close();
	}
}

关于换行符

\n可以实现换行,但是windows系统自带的记事本打开并没有换行,这是为什么呢?——因为windows识别的换行不是\n,而是\r\n

  • windows:\r\n
  • linux:\n
  • mac:\r

字符缓冲流

Reader有一个子类BufferedReader。子类继承父类显然子类可以重写父类的方法,也可以增加自己的新方法。例如一次读一行就是常用的操作。那么BufferedReader 类就提供了这个方法,可以查看readLine()方法具备 一次读取一个文本行的功能。很显然,该子类可以对功能进行增强。

两类字符缓冲流:
在这里插入图片描述 在这里插入图片描述

缓冲流的特殊功能(特殊方法):

  • BufferedWriter
    void newLine():写一个换行符,这个换行符由系统决定
  • BufferedReader
    String readLine():一次读取一行数据,但是不读取换行

缓冲流使用示例

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

public class Main {
	public static void main(String[] args) throws IOException {
		Wr();
		Re();
	}

	public static void Wr() throws IOException {
		File path = new File("c:\\users\\kyle\\desktop\\a.txt");
		FileWriter fw = new FileWriter(path);
		BufferedWriter bw = new BufferedWriter(fw);
		for(int i=0;i<10;i++) {
			bw.write(i + ": hello");
			bw.newLine();//相当于:bw.write("\r\n");
			bw.flush();
		}
		bw.close();
	}
	public static void Re() throws IOException {
		File path = new File("c:\\users\\kyle\\desktop\\a.txt");
		FileReader fr = new FileReader(path);
		BufferedReader br = new BufferedReader(fr);
		String line;
		while((line = br.readLine())!=null) {
			System.out.println(line);
		}
		fr.close();
	}
}
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值