Java IO 流(文件读写)
目录
File 类
- File 类介绍
- File 类构造方法
- File 类常用方法
字节流
- IO 流概述和分类
- 字节输出流
- 字节输入流
字节缓冲流
- BufferedInputStream
- BufferedOutputStream
字符流
- 编码
- 字符输出流
- 字符输入流
- 字符缓冲流
- 字符缓冲流特有方法
- 转换流
- Properties
File 类介绍
- 它是文件和目录的路径名的抽象表示。
- 文件和目录是可以通过 File 封装成对象的。
- 对于 File 而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是实际存在的,也可以是不存在的,将来是要通过具体的操作把这个路径的内容转换为具体的存在。
File 类构造方法
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File 实例 |
File(String parent, String child) | 通过父路径名字符串和子路径名字符串创建新的 File 实例 |
File(File parent, String child) | 通过父抽象路径名和子路径名字符串创建新的 File 实例 |
示例代码:
public class FileDemo { public static void main(String[] args) {
// File(String pathname): 通过将给定的路径名字符串转换为抽象路径名来创建新的 File 实例
File f1 = new File("E:\\test\\java.txt");
System.out.println(f1);
// File(String parent, String child): 通过父路径名字符串和子路径名字符串创建新的 File 实例
File f2 = new File("E:\\test", "java.txt");
System.out.println(f2);
// File(File parent, String child): 通过父路径对象和子路径名字符串创建新的 File 实例
File f3 = new File("E:\\test");
File f4 = new File(f3, "java.txt");
System.out.println(f4);
}
}
File 类常用方法
创建方法:
方法名 | 说明 |
---|---|
public boolean createNewFile() | 当文件不存在时,创建一个由该路径名命名的新空文件 |
public boolean mkdir() | 创建由此路径名命名的目录 |
public boolean mkdirs() | 创建由此路径名命名的目录,包括任何必需但不存在的父目录 |
public boolean renameTo(File dest) | 如果目标文件与源文件在同一路径下,那么 renameTo 的作用是重命名(文件与文件夹); 如果不在同一路径下,那么 renameTo 的作用是剪切,并且不能操作文件夹 |
删除方法:
方法 | 说明 |
---|---|
public boolean delete() | 删除由此抽象路径名表示的文件或目录。删除成功则返回 true |
deleteOnExit() | 等到 JVM 退出时才删除文件,一般用于删除临时文件 |
判断方法:
方法 | 说明 |
---|---|
public boolean isDirectory() | 测试此抽象路径名表示的 File 是否为目录 |
public boolean isFile() | 测试此抽象路径名表示的 File 是否为文件 |
public boolean exists() | 测试此抽象路径名表示的 File 是否真实存在 |
public boolean isHidden() | 测试此抽象路径名表示的 File 是否是一个隐藏的文件或文件夹 |
public boolean isAbsolute() | 测试此抽象路径名表示的 File 是否为绝对路径 |
获取方法:
方法名 | 说明 |
---|---|
public String getAbsolutePath() | 返回绝对路径 |
public String getPath() | 返回绝对路径(传什么返回什么) |
public String getName() | 获取文件或文件夹的名称,不包括上级路径 |
public String getAbsolutePath() | 获取绝对路径(与文件是否存在没关系) |
public long length() | 获取文件或文件夹的字节大小(路径不存在则返回 0) |
public String getParent() | 获取文件的父路径 |
public long lastModified() | 获取最后一次的修改时间(毫秒值) |
public File[] listFiles() | 把当前文件夹下面的所有子文件名与子文件夹名都使用了一个File对象描述,然后将这些对象存储到一个 File 数组中返回(文件或目录的绝对路径)。 (若对文件操作则返回 null) |
public String[] list() | 把当前文件夹下面的所有子文件名与子文件夹名(包括隐藏文件与隐藏文件夹)存储到一个 String 数组中返回(文件或目录名称)。 (若对文件操作则返回 null) |
public File[] list(FilenameFilter filter) | 返回指定路径中符合过滤条件的文件或文件夹(若对文件操作则返回 null) |
public String[] listFiles(FilenameFilter filter) | 返回指定路径中符合过滤条件的文件或文件夹(若对文件操作则返回 null) |
示例代码:
public class FileDemo { public static void main(String[] args) throws IOException {
// 创建文件
File f1 = new File("E:\\test\\java.txt");
System.out.println(f1.createNewFile());
System.out.println("--------");
// 删除刚创建的文件
f1.delete();
// 创建单级目录
File f2 = new File("E:\\test\\JavaSE");
System.out.println(f2.mkdir());
System.out.println("--------");
// 创建多级目录
File f3 = new File("E:\\test\\JavaWEB\\HTML");
// System.out.println(f3.mkdir()); // 报错
System.out.println(f3.mkdirs());
System.out.println("--------");
File f4 = new File("D:\\test\\test_delete.txt");
System.out.println(f4.getAbsolutePath()); // D:\test\test_delete.txt
System.out.println(f4.getAbsoluteFile()); // D:\test\test_delete.txt
System.out.println(f4.getPath()); // D:\test\test_delete.txt
System.out.println(f4.getName()); // test_delete.txt
File f5 = new File("D:\\testa\\testb");
System.out.println(f5.getName()); // testb
File file = new File("D:\\softwares");
File[] files = file.listFiles();
for(File f : files){
System.out.println(f); // 输出绝对路径
}
File file = new File("D:\\softwares");
String[] fileNames = file.list();
for(String fileName:fileNames){
System.out.println(fileName); // 只有名称
}
}
}
案例:列出指定路径下所有的 java 文件
- 方式 1:使用 listFiles()
import java.io.File;public class JavaBase {
public static void main(String[] args) {
findJavaFile1("d:\\JavaDemo");
}
public static void findJavaFile1(String pathName) {
File file = new File(pathName);
File[] files = file.listFiles();
for(File f : files){
if (f.isFile()&&f.getName().endsWith(".java")) {
System.out.println(f);
} else if (f.isDirectory()) {
findJavaFile1(f.getPath());
}
}
}
}
- 方式 2:使用 listFiles(FilenameFilter filter)
// 自定义一个文件名过滤器class MyFilter implements FilenameFilter{
public boolean accept(File dir, String name){
return name.endsWith(".java");
}
}
public class Test {
public static void main(String[] args){
File targetFile = new File("D:\\JavaPractise");
listJava(targetFile);
}
public static void listJava(File dir){
File[] files = dir.listFiles(new MyFilter());
for(File file : files){
System.out.println(file.getName());
}
}
}
字节流
IO 流概述和分类
IO 流介绍:
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输。
- IO 流就是用来处理设备间数据传输问题的。常见的应用有文件复制、文件上传、文件下载等。
IO 流的分类:
- 按照数据的流向:
- 输入流:读数据
- 输出流:写数据
- 按照数据类型来分:
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
- 字节流
IO 流体系:
字节流:字节流读取的是文件中的二进制数据,并不会转换成我们看得懂的字符。
InputStream:所有字节输入流的超类、抽象类。
- FileInputStream:读取文件的二进制数据。
- BufferedInputStream:缓冲输入字节流。为了提高读取文件数据的效率。该类内部维护了一个 8KB 的字节数组。
OutputStream:所有字节输出流的超类、抽象类。
- FileOutputStream:向文件输出数据。
- BufferedOutputStream:缓冲输出字节流。内部也是维护了8KB的字节数组。
字符流:字符流会把读取到的二进制数据进行对应的编码与解码。字符流=字节流+编码/解码
Reader:所有字符输入流的超类、抽象类。
- FileReader:读取文件的字符数据。
- BufferedReader:缓冲输入字符流;出现的目的是为了提高读取文件字符的效率和拓展了 FileReader 的功能。该类内部维护了 8192 长度的字符数组。
Writer:所有字符输出流的超类、抽象类。
- FileWriter:向文件输出字符数据;内部维护了一个 1KB 的字符数组。
- BufferedWriter:缓冲输出字符流;出现的目的是为了提高写数据的效率和拓展了 FileWriter 的功能。该类只不过是内部维护了更大的 8192 长度的字符数组,与多了 newline 方法。
IO 流使用场景:
- 如果操作的是纯文本文件,优先使用字符流。
- 如果操作的是图片、视频、音频等二进制文件,优先使用字节流。
- 如果不确定文件类型,优先使用字节流,字节流是万能的流。
字节输出流
字节流抽象基类:
- InputStream:这个抽象类是表示字节输入流的所有类的超类。
- OutputStream:这个抽象类是表示字节输出流的所有类的超类。
- 子类名特点:子类名称都是以其父类名作为子类名的后缀。
字节输出流:
- FileOutputStream(String name):创建文件输出流以指定的名称写入文件。
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建文件和字节输出流对象,让字节输出流对象指向文件)。
- 调用字节输出流对象的写数据方法,把字符串数据转换成字节数组写出到文件。
- 释放资源(关闭此文件输出流,并释放与此流相关联的任何系统资源),原则:先开后关,后开先关。
注意事项:
- 如果目标文件不存在,那么会自动创建目标文件。
- 如果目标文件已存在,那么会先清空目标文件中的数据,然后再写入。
- 如果想追加内容,使用 new FileOutputStream(file,true),如果第二个参数为 true,则字节将写入文件的末尾而不是开头。
- 虽然 write() 方法接收 int 类型的数据,但是真正写出的只是一个字节的数据,只是把低 8 位的二进制数据写出,其他 24 位数据全部丢弃。
- write(buf, 0, 2):从字节数组的指定索引值开始写,写出两个字节。
- 每新创建一个 FileInputStream 对象时,默认情况下 FileOutputStream 的指针是指向了文件的开头位置。每写出一次,指针都会相应地移动。
示例代码:
import java.io.FileOutputStream;import java.io.IOException;
public class JavaBase {
public static void main(String[] args) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("d:\\test_output_stream.txt", true);
fileOutputStream.write(100); // 实时写入"d"
String str = "abcd";
fileOutputStream.write(str.getBytes(), 1, 2); // 追加写入"bc"
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字节输入流
字节输入流:
- FileInputStream(String name):通过与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名 name 命名。
FileInputStream 读取方法:
- public int read():一次读取一个字节,返回值是读取到的内容。返回 -1 则表示读取完毕。
- public int read(byte[] b):一次读取 b 个字节大小的数据。内容是存储到缓冲数组(b)中,返回值是存储到缓冲数组中的字节个数。返回 -1 则表示读取完毕。
字节输入流读取数据的步骤:
- 创建字节输入流对象。
- 调用字节输入流对象的读数据方法。
- 释放资源(原则:先开后关,后开先关)。
示例:
import java.io.FileInputStream;import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
// 1.读取目标文件
File file = new File("D:\\abc.txt");
// 2.建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 保存每次读取到的字节个数
int length = 0;
// 3.存储读取到的数据。缓冲数组的长度一般是1024的倍数
byte[] buf = new byte[4];
// read() 方法如果读取到了文件的末尾,就会返回 -1
while((length=fileInputStream.read(buf)) != -1){
System.out.println(new String(buf, 0, length)); // 每次读取的内容
}
// 4.关闭资源
fileInputStream.close();
}
}
示例:字节流复制文件
import java.io.FileInputStream;import java.io.FileOutputStream;
import java.io.IOException;
public class JavaBase {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
// 根据数据源创建字节输入流对象
fileInputStream = new FileInputStream("E:\\mn.jpg");
// 根据目的地创建字节输出流对象
fileOutputStream = new FileOutputStream("myByteStream\\mn.jpg");
// 读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
byte[] bys = new byte[1024];
int len;
while ((len=fileInputStream.read(bys))!=-1) {
fileOutputStream.write(bys, 0, len);
}
} catch (IOException e) {
/* 1. 首先要阻止后面的代码执行。因为前面的数据已经读取异常,后面的数据执行代码已无意义,并需要通知使用者这里出错了。
因此使用 throw,方法既会停止执行,并且也能抛出通知。
2. 把IOException传递给RuntimeException包装一层,然后再抛出,目的是为了使用者使用变得更加灵活。
使用者对RuntimeException可处理也可不处理。
*/ System.out.println("读取文件出错...");
throw new RuntimeException(e);
} finally {
// 关闭资源。原则:先开后关,后开先关
try{
if(fileOutputStream!=null){ // 如果读取的文件不存在,管道也就没建立起来,就会出现空指针异常,也就不需要关
fileOutputStream.close();
System.out.println("关闭输出流成功");
}
}catch(IOException e){ // 再出错一般就是硬件问题
System.out.println("关闭输出流失败");
throw new RuntimeException(e);
}finally{
try{
if(fileInputStream!=null){
fileInputStream.close();
System.out.println("关闭输入流成功");
}
}catch(IOException e){
System.out.println("关闭输入流失败");
throw new RuntimeException(e);
}
}
}
}
}
字节缓冲流
构造方法:
方法名 | 说明 |
---|---|
BufferedOutputStream(OutputStream out) | 创建字节缓冲输出流对象 |
BufferedInputStream(InputStream in) | 创建字节缓冲输入流对象 |
BufferedInputStream
使用步骤:
- 找到目标文件。
- 建立数据的输入通道。
- 建立缓冲输入字节流(需要传递 InputStream,因此传递 FileInputStream)。
- 关闭资源(调用 BufferedInputStream 的 close 方法实际上关闭的是 FileInputStream)。
疑问 1:为什么创建 BufferedInputStream 的时候需要传递 FileInputStream?
- 答:因为
凡是缓冲流都不具备读写文件的能力
,因此需要借助 FileInputStream 来读取文件的数据。
疑问 2:BufferedInputStream 的出现是为了提高读取文件的效率,但是 BufferedInputStream 的 read 方法每次只读取一个字节的数据,而 FileInputStream 每次也是读取一个字节的数据,那么 BufferedInputStream 如何提高效率?
- 答:BufferedInputStream 是先将硬盘数据存入内部数组,再从数组中读取数据,相当于从内存中读取数据的速度;而 FileInputStream 相当于每次直接从硬盘读取数据。
BufferedOutputStream
使用步骤:
- 找到目标文件
- 建立数据的输出通道
- 建立缓冲输出字节流
- 把数据写出
- 把数据写到硬盘中,flush 与 close 均可。
注意:
使用 BufferedOutputStream 写数据的时候,write 方法是先把数据写到内部的字节数组中;如果需要把数据真正地写到硬盘上,需要调用 flush 方法或者 close 方法(而 FileOutputStream 的 write 则是实时写入文件内容),或者是内部维护的 8KB 的字节数组已经填满数据的时候。
综合示例:使用字节缓冲输入/输出流复制文件
public class CopyAviDemo { public static void main(String[] args) throws IOException {
method1();
method2();
}
// 方式一:字节缓冲流一次读写一个字节数组
public static void method2() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys)) != -1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
// 方式二:字节缓冲流一次读写一个字节
public static void method1() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
int by;
while ((by=bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
}
}
字符流
字符流介绍:
- 由于字节流操作中文不是特别得方便,所以 Java 就提供字符流。
- 字符流会把读取到的二进制数据进行对应的编码与解码(字符流 = 字节流 + 编码/解码)。
中文的字节存储方式:
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,那么如何识别是中文的呢?
- 字节流 write 能够写中文是因为借助了字符串的 getBytes 方法对字符串进行了编码(字符 ---> 数字);
- 字节流 read 能够读中文是因为借助了字符串的 new String() 对字符串进行了解码(数字 ---> 字符);
- 同时记事本本身具有解码的功能。
编码
编码介绍详见:《编码》
相关方法:
方法名 | 说明 |
---|---|
byte[] getBytes() | 使用平台的默认字符集将该 String 编码为一系列字节 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该 String 编码为一系列字节 |
String(byte[] bytes) | 使用平台的默认字符集解码指定的字节数组来创建字符串 |
String(byte[] bytes, String charsetName) | 通过指定的字符集解码指定的字节数组来创建字符串 |
代码示例:
public class StringDemo { public static void main(String[] args) throws UnsupportedEncodingException {
// 定义一个字符串
String s = "中国";
// 编码
// byte[] bys = s.getBytes(); // [-28, -72, -83, -27, -101, -67]
// byte[] bys = s.getBytes("UTF-8"); // [-28, -72, -83, -27, -101, -67]
byte[] bys = s.getBytes("GBK"); // [-42, -48, -71, -6]
System.out.println(Arrays.toString(bys));
// 解码
// String ss = new String(bys);
// String ss = new String(bys, "UTF-8");
String ss = new String(bys, "GBK");
System.out.println(ss);
}
}
字符输出流
介绍:
- Writer: 用于写入字符流的抽象父类。
- FileWriter: 用于写入字符流的常用子类。
构造方法:
方法名 | 说明 |
---|---|
FileWriter(File file) | 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter(File file, boolean append) | 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter(String fileName) | 根据给定的文件名构造一个 FileWriter 对象 |
FileWriter(String fileName, boolean append) | 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 |
成员方法:
方法名 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
刷新和关闭的方法:
方法名 | 说明 |
---|---|
flush() | 刷新流,之后还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
注意事项:
- Filewriter 内部是维护了一个 1KB 的字符数组的,写数据的时候会先写入到内部的字符数组中,如果需要把数据真正写到硬盘上,需要调用 flush 或 close 方法。
- 如果目标文件不存在,会自动创建目标文件。
- 如果在原有的文件上追加数据,需要使用 new FileWriter(file, true),只有创建新的 FileWriter 对象时才会把指针放在文件开头处。
示例:
public class OutputStreamWriterDemo { public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("myCharStream\\a.txt");
// void write(int c):写一个整数
// fw.write(97);
// fw.write(98);
// fw.write(99);
// void writ(char[] cbuf):写入一个字符数组
char[] chs = {'a', 'b', 'c', 'd', 'e'};
// fw.write(chs);
// void write(char[] cbuf, int off, int len):写入字符数组的一部分
// fw.write(chs, 0, chs.length);
// fw.write(chs, 1, 3);
// void write(String str):写一个字符串(具备编码的功能)
// fw.write("abcde");
// void write(String str, int off, int len):写字符串的一部分
// fw.write("abcde", 0, "abcde".length());
fw.write("abcde", 1, 3);
// 释放资源
fw.close();
}
}
字符输入流
介绍:
- Reader: 用于读取字符流的抽象父类。
- FileReader: 用于读取字符流的常用子类。
构造方法:
方法名 | 说明 |
---|---|
FileReader(File file) | 在给定从中读取数据的 File 的情况下创建一个新 FileReader |
FileReader(String fileName) | 在给定从中读取数据的文件名的情况下创建一个新 FileReader |
成员方法:
方法名 | 说明 |
---|---|
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
代码示例:
public class InputStreamReaderDemo { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("myCharStream\\b.txt");
// int read():一次读一个字符数据
// int ch;
// while ((ch=fr.read())!=-1) {
// System.out.print((char)ch);
// }
// int read(char[] cbuf):一次读一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
// 释放资源
fr.close();
}
}
注意:
Java 默认使用的是 GBK 编码表,如果 FileReader 读到的数据找不到对应的字符,那么会返回一个未知字符对应的数字,未知字符占一个字节。因此如果用字符流拷贝图片,图片会有部分数据丢失而打不开。
综合示例:字符输入/输出流 边读边写拷贝数据
public static void main(String[] args) throws IOException { // 找到目标文件 File inFile = new File("D:\\abc.txt");
File outFile = new File("E:\\a.txt");
// 建立数据的输入通道
FileReader fileReader = new FileReader(inFile);
FileWriter fileWriter = new FileWriter(outFile);
char[] buf = new char[1024];
if(fileReader.read(buf) != -1){
fileWriter.write(buf);
}
fileWriter.close();
fileReader.close();
}
字符缓冲流
字符缓冲流介绍:
- BufferedWriter:将文本写入字符输出流并缓冲字符,以提供单个字符、数组和字符串的高效写入。可以指定缓冲区大小或者使用默认大小。默认值已足够大,可用于大多数用途。
- BufferedReader:从字符输入流读取文本并缓冲字符,以提供字符、数组和行的高效读取。可以指定缓冲区大小或者使用默认大小。 默认值已足够大,可用于大多数用途。
构造方法:
方法名 | 说明 |
---|---|
BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
示例代码:
public class BufferedStreamDemo { public static void main(String[] args) throws IOException {
// BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
// BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
// 一次读取一个字符数据
// int ch;
// while ((ch=br.read())!=-1) {
// System.out.print((char)ch);
// }
// 一次读取一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
System.out.print(new String(chs, 0, len));
}
br.close();
}
}
字符缓冲流特有方法
BufferedWriter:
方法名 | 说明 |
---|---|
void newLine() | 写入一个行分隔符(行分隔符字符串由系统属性定义) |
BufferedReader:
方法名 | 说明 |
---|---|
String readLine() | 读一行文字。结果包含行的内容的字符串,不包括任何行终止字符。如果流的结尾已经到达,则为 null |
示例:使用步骤与自己实现 readline
public static void main(String[] args) throws IOException { // 1.找到目标文件
File file = new File("D:\\abc.txt");
// 2.建立数据的输入通道
FileReader fileReader = new FileReader(file);
// 3.建立缓冲输入字符流
BufferedReader bufferedReader = new BufferedReader(fileReader);
// 4.读取数据
/* char content = (char) bufferedReader.read();
// 读取一个字符。
System.out.println(content);*/
// 使用BufferedReader拓展的功能readLine(): 一次读取一行,如果读到末尾返回null
String line = null;
while((line = bufferedReader.readLine())!=null){
System.out.println(line);
} // 虽然readline每次读取一行数据,但是读到的line是不包含\r\n的
}
// 自己实现readLine方法
public static String myReadLine(FileReader fileReader) throws IOException{
// 创建一个字符串缓冲类用于存储读取到的数据
StringBuilder sb = new StringBuilder();
int content = 0;
while((content=fileReader.read())!=-1){
// 遇到\r则不读取数据,遇到\n则结束
if(content =='\r'){
continue;
}else if(content =='\n'){
break;
}else{
// 普通字符
sb.append((char)content);
}
}
// 代表已经读取完毕
if(content==-1){
return null;
}
return sb.toString(); // 如果没有内容,返回的是"",不是null
}
// 实现自己的readline方法循环输出全部数据
while((line=myReaderLine(fileReader))! =null){
System.out.println(line);
}
示例:使用字符缓冲流读取文件中的数据,排序后再次写到本地文件
public class CharStreamDemo14 { public static void main(String[] args) throws IOException {
// 1. 把文件中的数据读取进来
BufferedReader br = new BufferedReader(new FileReader("charstream\\sort.txt"));
// 输出流一定不能写在这里,否则会先清空文件中的内容
// BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\sort.txt"));
String line = br.readLine();
System.out.println("读取到的数据为" + line);
br.close();
// 2. 按照空格进行切割
String[] split = line.split(" "); // 9 1 2 5 3 10 4 6 7 8
// 3. 把字符串数组变成int数组
int [] arr = new int[split.length];
// 遍历split数组,可以进行类型转换
for (int i=0; i < split.length; i++) {
String smallStr = split[i];
// 类型转换
int number = Integer.parseInt(smallStr);
// 把转换后的结果存入到arr中
arr[i] = number;
}
// 4. 排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// 5. 把排序之后结果写回到本地 1 2 3 4...
BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\sort.txt"));
// 写出
for (int i = 0; i < arr.length; i++) {
bw.write(arr[i] + " ");
bw.flush();
}
// 释放资源
bw.close();
}
}
转换流
InputStreamReader:是从字节流到字符流的桥梁,父类是 Reader。
- 它读取字节,并使用指定的编码将其解码为字符。
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
OutputStreamWriter:是从字符流到字节流的桥梁,父类是 Writer。
- 使用指定的编码将写入的字符编码为字节。
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
作用:
- 如果目前所获取到的是一个字节流,且需要转换成字符流使用,这时就可以使用转换流。
- 使用转换流可以指定编码表进行读写文件(FileReader/Writer 不能指定码表)。
构造方法:
方法名 | 说明 |
---|---|
InputStreamReader(InputStream in) | 使用默认字符编码创建 InputStreamReader 对象 |
InputStreamReader(InputStream in, String chatset) | 使用指定的字符编码创建 InputStreamReader 对象 |
OutputStreamWriter(OutputStream out) | 使用默认字符编码创建 OutputStreamWriter 对象 |
OutputStreamWriter(OutputStream out, String charset) | 使用指定的字符编码创建 OutputStreamWriter 对象 |
示例:
public class Test { public static void main(String[] args) throws IOException {
readTest();
writeTest();
writeTest2();
readTest2();
}
// 输出字节流的转换流
public static void writeTest() throws IOException{
File file = new File("D:\\writeTest.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//fileOutputStream.write("abc".getBytes());
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
outputStreamWriter.write("大家好");
outputStreamWriter.close();
}
// 使用输出字节流的转换流指定码表写出数据
public static void writeTest2() throws IOException{
File file = new File("D:\\writeTest2.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//fileOutputStream.write("abc".getBytes());
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"UTF-8");
outputStreamWriter.write("大家好,这用了UTF-8");
outputStreamWriter.close();
}
// 输入字节流的转换流
public static void readTest() throws IOException{
InputStream inputStream = System.in; // 获取了标准的输入流
// System.out.println("读到的字符:"+(char)inputStream.read()); // 只能读一个字节
// 为了使用BufferedReader的readline方法,要先把字节流转换成字符流
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader); // 需要输入Reader,即字符流
String line = null;
while((line=bufferedReader.readLine())!=null){
System.out.println("读到的字符:"+line);
}
}
// 使用输入字节流的转换流指定码表读取数据
public static void readTest2() throws IOException{
File file = new File("D:\\writeTest2.txt");
FileInputStream fileInputStream = new FileInputStream(file);
// 创建字节流的转换流并且指定码表进行读取
InputStreamReader inutStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
char[] buf = new char[1024];
int length = 0;
while((length=inutStreamReader.read(buf))!=-1){
System.out.println(new String(buf));
}
}
}
Properties
Properties 介绍:
- 是一个 Map 体系的集合类。
- 主要用于生成配置文件与读取配置文件的信息。
- 元素中的键及其对应的值都是一个字符串。
- 可以保存到流中或从流中加载。
常用方法:
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是 String 类型,底层调用 Hashtable 方法 put |
String getProperty(String key) | 使用此属性列表中指定的键搜索对应的值 |
Set<String> stringPropertyNames() | 从该属性列表中返回一个不可修改的键值对,其中键及其对应的值是字符串 |
void load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此 Properties 表中,以适合使用 load(Reader) 方法的格式写入输出字符流 |
示例:
public class Test { public static void main(String[] args) throws FileNotFoundException, IOException {
//creatProperties();
readProperties();
}
// 读取配置文件的信息
public static void readProperties() throws FileNotFoundException, IOException{
// 1.创建Properties对象
Properties properties = new Properties();
// 2.把配置文件的信息加载到Properties中
properties.load(new FileReader("D:\\aa.properties"));
// 3.遍历查看Properties中的信息是否加载成功
Set<Entry<Object, Object>> entrys = properties.entrySet();
for(Entry<Object, Object> entry : entrys){
System.out.println("键:"+entry.getKey()+" 值"+entry.getValue());
}
// 修改狗娃的密码
properties.setProperty("狗娃", "1234");
properties.store(new FileWriter("D:\\aa.properties"), "hehe");
}
// 生成配置文件
public static void creatProperties() throws FileNotFoundException, IOException{
// 1.创建Properties对象
Properties properties = new Properties();
properties.setProperty("狗娃", "123");
properties.setProperty("狗剩", "234");
// 2.使用Properties生成配置文件
// 第一个参数是一个输出流对象;第二个参数是使用一个字符串描述这个配置文件的信息。
// properties.store(new FileOutputStream("D:\\aa.properties"), "haha");
properties.store(new FileWriter("D:\\aa.properties"), "haha");
}
}
案例:使用配置文件记录软件使用次数,若试用超过 3 次则提醒购买正版
public class Test { public static void main(String[] args) throws IOException {
File file = new File("D:\\count.properties");
if(!file.exists()){
// 如果配置文件不存在,则创建配置信息
file.createNewFile();
}
// 创建Properties对象
Properties properties = new Properties();
// FileOutputStream fileOutputStream = new FileOutputStream(file);
// 注意:若使用上面语句会清空文件内容,因此永远都是使用一次,因此至少要放在load语句后面
// 把配置文件的信息加载到Properties中
properties.load(new FileInputStream(file));
int count = 0; // 定义该变量用于记录使用次数
// 读取配置文件的运行次数
String value = properties.getProperty("count"); // 通过key获取value
if(value!=null){
count = Integer.parseInt(value);
}
// 判断使用次数是否超过3次
if(count==3){
System.out.println("您的试用次数已超过3次,请购买正版!");
System.exit(0);
}
count++;
System.out.println("您已经试用了本软件第"+count+"次");
properties.setProperty("count", count+"");
// 生成配置文件
properties.store(new FileOutputStream(file), "Run times");
}
}
以上是 Java IO 流(文件读写) 的全部内容, 来源链接: utcz.com/z/390548.html