字符流读写文本文件

字符流

当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

输入流

输入字符流(Reader)

java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。下面是Reader的体系:

字符流读写文本文件_第1张图片

public abstract class Reader implements Readable, Closeable

它是个抽象类,因此不能被实例化。

构造方法

Reader提供了两个构造方法供子类使用

protected Reader() 
protected Reader(Object lock) 

实例方法

它定义了字符输入流的基本共性功能方法。

  • public void close() :关闭此流并释放与此流相关联的任何系统资源。
  • public int read() : 从输入流读取一个字符。
  • public int read(char[] cbuf) : 从输入流中读取一些字符
  • public abstract int read(char[] cbuf, int off, int len) : 从输入流中读取一些字符
  • public int read(CharBuffer target):将字符读入指定的字符缓冲区
  • public void mark(int readAheadLimit):标记流中的位置
  • boolean markSupported(): 是否支持 mark
  • public boolean ready() : 流是否准备好被读取
  • public void reset() : 重置流
  • public long skip(long n): 跳过字符

由于public abstract int read(char[] cbuf, int off, int len) 是抽象方法,所以所有子类必须实现此方法。

JDK10提供public long transferTo(Writer out)用于写出读取到的字符

FileReader

java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

JDK11提供的构造方法中可以传入指定编码

public class FileReader extends InputStreamReader

系统默认字符编码:

Charset.defaultCharset(); // 系统默认编码
  • eclipse中默认为GBK
  • jetbrains idea中默认UTF8

编辑器的默认编码是可以更改的

构造方法

  • FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。
  • FileReader(String fileName) : 创建一个新的 FileReader ,给定要读取的文件的名称。

JDK11新增的构造

FileReader(File file, Charset charset)
FileReader(String fileName, Charset charset)

例子:

File file = new File("D:\\temp\\a.txt");
FileReader reader = new FileReader(file);
FileReader reader1 = new FileReader("D:\\temp\\a.txt");

构造方法内部都是调用了父类的构造方法,传入一个FileInputStream对象。

实例方法

FileReader中的所有方法都来自其父类InputStreamReader,没有重写任何方法同时也没有扩展的方法。也就是说,学习了FileReader同时也学习了InputStreamReader.

读取单个字符

read() 方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回 -1 ,循环读取

package com.itlaobing.tor;

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

public class FileReaderTest {

	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("D:/temp/reader.txt");
		int ch = fr.read();//读取单个字符
		System.out.println((char)ch);
		fr.close();//关闭流
	}
}

自行将上面代码修改为读取整个文本内容。

读取多个字符

read(char[] cbuf) ,每次读取cbuf的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回 -1

创建reader2.txt内容为:

云创动力在西安学习中心

例子:

package com.itlaobing.tor;

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

public class FileReaderTest2 {

	public static void main(String[] args) throws IOException {
		// 使用文件名称创建流对象
		FileReader fr = new FileReader("D:/temp/reader2.txt");
		// 定义变量,保存有效字符个数
		int len;
		// 定义字符数组,作为装字符数据的容器
		char[] cbuf = new char[2];
		// 循环读取
		while ((len = fr.read(cbuf)) != -1) {
			System.out.println(new String(cbuf));
		}
		// 关闭资源
		fr.close();
	}

}

输入结果为:

云创
动力
在西
安学
习中
心中

我们发现多了一个字符,这是为什么呢?尝试将代码中的:

System.out.println(new String(cbuf));

修改为:

System.out.println(new String(cbuf, 0, len));

BufferedReader

java.io.BufferedReader 从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。 它是一个缓冲流。

public class BufferedReader extends Reader

构造方法

BufferedReader提供了两个构造方法

//创建使用默认大小的输入缓冲区的缓冲字符输入流
public BufferedReader(Reader in)
//创建使用指定大小的输入缓冲区的缓冲字符输入流
public BufferedReader(Reader in, int sz)

读取一行字符

BufferedReader继承了Reader中所有public方法,还扩展了一个方法:

public String readLine() //读取一行文字

readLine()读取完毕时,返回null

创建bufferReader.txt文件,并写入如下内容:

床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。

例子:

package com.itlaobing.demo.pm;

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

public class BufferedReaderTest {

	public static void main(String[] args) throws IOException {
		// 创建流对象
		BufferedReader reader = new BufferedReader(new FileReader("D:/temp/bufferReader.txt"));
		// 定义字符串,保存读取的一行文字
		String line = null;
		// 循环读取,读取到最后返回null
		while ((line = reader.readLine()) != null) {
			System.out.print(line);
			System.out.println("------");
		}
		// 关闭流
		reader.close();
	}

}

InputStreamReader

java.io.InputStreamReaderReader的子类,是从字节流到字符流的桥:它读取字节,并使用指定的Charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

public class InputStreamReader extends Reader

构造方法

InputStreamReader中提供了四个构造方法:

//创建一个使用默认字符集的InputStreamReader
public InputStreamReader(InputStream in)
//创建一个使用命名字符集的InputStreamReader
public InputStreamReader(InputStream in, String charsetName)
//创建一个使用给定字符集的InputStreamReader
public InputStreamReader(InputStream in, Charset cs)
//创建一个使用给定字符集解码器的InputStreamReader
public InputStreamReader(InputStream in, CharsetDecoder dec)

其中常用的是前三个。

实例方法

InputStreamReader继承了Reader中的所有public方法,并扩展了getEncoding()方法。

public String getEncoding()//获取使用的字符编码名称

其他方法在之前都有讲过,所以在此不再描述。

指定编码读取

在创建InputStreamReader对象时,指定编码字符集。

例子:

创建InputStreamReader.txt文件,内容如下:

大家好,我是渣渣辉。
是兄弟就来**蓝月砍我。
package com.itlaobing.demo.pm;

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

public class InputStreamReaderTest {

	public static void main(String[] args) throws IOException {
		// 定义文件路径,文件为gbk编码
		String FileName = "D:\\temp\\InputStreamReader.txt";
		
		// 创建流对象,默认UTF8编码
		InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
		// 创建流对象,指定GBK编码
		InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName), "GBK");
		// 定义变量,保存字符
		int read;
		// 使用默认编码字符流读取,乱码
		while ((read = isr.read()) != -1) {
			System.out.print((char) read); 
		}
		isr.close();
		System.out.println();
		
		// 使用指定编码字符流读取,正常解析
		while ((read = isr2.read()) != -1) {
			System.out.print((char) read);
		}
		isr2.close();
	}

}

输出结果如下:

��Һã����������ԡ�
���ֵܾ���**���¿��ҡ�
大家好,我是渣渣辉。
是兄弟就来**蓝月砍我。

输出流

字符输出流【Writer】

java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。下面是Writer的体系:

字符流读写文本文件_第2张图片

public abstract class Writer implements Appendable, Closeable, Flushable

构造方法

Writer提供了两个构造方法:

protected Writer();
protected Writer(Object lock)

实例方法

Writer类中提供了以下方法:

  • public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
  • public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。
  • public void write(int c) :写出一个字符。
  • public void write(char[] cbuf) :将 cbuf.length字符从指定的字符数组写出此输出流。
  • public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
  • public void write(String str) :写出一个字符串。

FileWriter

java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

public class FileWriter extends OutputStreamWriter

构造方法

FileWriter类提供了5个构造方法:

//构造一个给定文件名的FileWriter对象
public FileWriter(String fileName);
//构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据
public FileWriter(String fileName, boolean append);
//给一个File对象构造一个FileWriter对象
public FileWriter(File file);
//给一个File对象构造一个FileWriter对象
public FileWriter(File file, boolean append);
//构造与文件描述符关联的FileWriter对象
public FileWriter(FileDescriptor fd) 

常用的是前4个构造方法。

JDK11新增的构造

public FileWriter(String fileName, Charset charset)
public FileWriter(String fileName, Charset charset, boolean append)
public FileWriter(File file, Charset charset)
public FileWriter(File file, Charset charset, boolean append)   

实例方法

FileWriter类中的所有方法都来自其父类OutputStreamWriter,没有重写任何方法同时也没有扩展的方法。也就是说,学习了FileWriter同时也学习了OutputStreamWriter

写出单个字符

write(int b) 方法,每次可以写出一个字符数据。

例子:

package com.itlaobing.demo.pm;

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

public class FileWriterTest {

	public static void main(String[] args) throws IOException {
		FileWriter writer = new FileWriter("D:/temp/fileWriter.txt");
		
		writer.write(97); //a
		writer.write('a'); //a
		writer.write("你好"); //你好
		 
		
		writer.flush();//刷新缓冲区,流对象可以继续使用
		writer.close();//关闭流,释放系统资源。关闭前会刷新缓冲区
	}
}

执行完以上代码后,在D:/temp/文件夹中会多出一个fileWriter.txt文件,文件内容是:

aa你好

文件的字符编码集是系统默认的字符编码集,此处我们的默认编码集是UTF-8

写出多个字符

  • write(char[] cbuf)
  • write(char[] b, int off, int len)

BufferedWriter

java.io.BufferedWriter是将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。 可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。是一个缓冲流。

public class BufferedWriter extends Writer

构造方法

BufferedWriter提供了两个构造方法:

//创建使用默认大小的输出缓冲区的缓冲字符输出流
public BufferedWriter(Writer out);
//创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区
public BufferedWriter(Writer out, int sz);

实例方法

BufferedWriter继承了Writer中所有public方法,还扩展了一个方法:

public void newLine();//写一个行分隔符,由系统属性定义符号

例子:

package com.itlaobing.tor;

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

public class BufferWriterTest {

	public static void main(String[] args) throws IOException {
		// 创建流对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("d:/temp/bufferedWriter.txt"));
		// 写出数据
		bw.write("云创动力");
		// 写出换行
		bw.newLine();
		bw.write("XX学院");
		bw.newLine();
		bw.write("IT特种兵");
		bw.newLine();
		// 释放资源
		bw.close();

	}
}

运行以上程序后,会在创建一个新文件,编码字符集为默认编码字符集,此处为UTF-8,内容为:

云创动力
XX学院
IT特种兵

OutputStreamWriter

java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

public class OutputStreamWriter extends Writer

构造方法

OutputStreamWriter提供了四个构造方法:

//创建一个使用默认字符编码的OutputStreamWriter
public OutputStreamWriter(OutputStream out);
//创建一个使用命名字符集的OutputStreamWriter。
public OutputStreamWriter(OutputStream out, String charsetName);
//创建一个使用给定字符集的OutputStreamWriter
public OutputStreamWriter(OutputStream out, Charset cs);
//创建一个使用给定字符集编码器的OutputStreamWriter
public OutputStreamWriter(OutputStream out, CharsetEncoder enc);

实例方法

OutputStreamWrter的方法大都继承自Writer,除了getEncoding()方法。

例子:

package com.itlaobing.tor;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;

public class OutputStreamWriterTest {

	public static void main(String[] args) throws IOException {
		FileOutputStream out = new FileOutputStream("d:/temp/outStreamWriter.txt");
		Charset set = Charset.forName("utf-8");
		OutputStreamWriter writer = new OutputStreamWriter(out, set);
		System.out.println("编码格式为: " + writer.getEncoding());
		writer.write("站在那别动,我去买橘子");
		writer.close();
	}

}

增强try

JDK 7之前我们使用try-catchtry-catch-finally来处理异常。在使用资源的时最后都需要关闭资源,所以一般我们在finally处关闭资源。比如:

public static void main(String[] args) throws IOException {
		FileOutputStream out = null;
		OutputStreamWriter writer = null;
		try {
			out = new FileOutputStream("d:/temp/outStreamWriter.txt");
			Charset set = Charset.forName("utf-8");
			writer = new OutputStreamWriter(out, set);
			System.out.println("编码格式为: " + writer.getEncoding());
			writer.write("站在那别动,我去买橘子");
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
            //关闭资源
			writer.close();
			out.close();
		}
	}

然而有的时候我们会忘记关闭资源。那么有没有更好的方法呢?

jdk1.7开始, Java 7增强了try语句的功能——它允许在try关键字后跟一对圆括号(),圆括号可以声明,初始化一个或多个资源,此处的资源指得是那些必须在程序结束时必须关闭的资源(比如流操作,数据库连接,网络连接等),try语句在该语句结束时自动关闭这些资源。这种称为try-with-resources语句

Charset set = Charset.forName("utf-8");
		try (FileOutputStream out = new FileOutputStream("d:/temp/outStreamWriter.txt"); OutputStreamWriter writer = new OutputStreamWriter(out, set);){
			System.out.println("编码格式为: " + writer.getEncoding());
			writer.write("站在那别动,我去买橘子");
		} catch (IOException e) {
			e.printStackTrace();
		}

像这样的话,执行完会自动关闭,不用我们在finally中关闭,也再也不用担心忘记关闭了。

注意:只要这些资源实现类实现了CloseableAutoCloseable接口,就可以自动关闭。几乎所有的资源都可以用这种方式实现自动关闭资源。

如果try()里面有多个资源,用;分开,资源的close方法的调用顺序与它们的创建顺序相反。带有资源的try语句可以像一般的try语句一样具有catch和finally块。在try-with-resources语句中,任何catch或finally块都是在声明的资源被关闭后才会执行的

你可能感兴趣的:(python,开发语言)