Java IO 流(文件读写)

java

目录

  • 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):创建文件输出流以指定的名称写入文件。

使用字节输出流写数据的步骤:

  1. 创建字节输出流对象(调用系统功能创建文件和字节输出流对象,让字节输出流对象指向文件)。
  2. 调用字节输出流对象的写数据方法,把字符串数据转换成字节数组写出到文件。
  3. 释放资源(关闭此文件输出流,并释放与此流相关联的任何系统资源),原则:先开后关,后开先关。

注意事项:

  1. 如果目标文件不存在,那么会自动创建目标文件。
  2. 如果目标文件已存在,那么会先清空目标文件中的数据,然后再写入。
  3. 如果想追加内容,使用 new FileOutputStream(file,true),如果第二个参数为 true,则字节将写入文件的末尾而不是开头。
  4. 虽然 write() 方法接收 int 类型的数据,但是真正写出的只是一个字节的数据,只是把低 8 位的二进制数据写出,其他 24 位数据全部丢弃。
  5. write(buf, 0, 2):从字节数组的指定索引值开始写,写出两个字节。
  6. 每新创建一个 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 则表示读取完毕。

字节输入流读取数据的步骤:

  1. 创建字节输入流对象。
  2. 调用字节输入流对象的读数据方法。
  3. 释放资源(原则:先开后关,后开先关)。

示例:

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

使用步骤:

  1. 找到目标文件。
  2. 建立数据的输入通道。
  3. 建立缓冲输入字节流(需要传递 InputStream,因此传递 FileInputStream)。
  4. 关闭资源(调用 BufferedInputStream 的 close 方法实际上关闭的是 FileInputStream)。

疑问 1:为什么创建 BufferedInputStream 的时候需要传递 FileInputStream?

  • 答:因为凡是缓冲流都不具备读写文件的能力,因此需要借助 FileInputStream 来读取文件的数据。

疑问 2:BufferedInputStream 的出现是为了提高读取文件的效率,但是 BufferedInputStream 的 read 方法每次只读取一个字节的数据,而 FileInputStream 每次也是读取一个字节的数据,那么 BufferedInputStream 如何提高效率?

  • 答:BufferedInputStream 是先将硬盘数据存入内部数组,再从数组中读取数据,相当于从内存中读取数据的速度;而 FileInputStream 相当于每次直接从硬盘读取数据。

BufferedOutputStream

使用步骤:

  1. 找到目标文件
  2. 建立数据的输出通道
  3. 建立缓冲输出字节流
  4. 把数据写出
  5. 把数据写到硬盘中,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()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

注意事项:

  1. Filewriter 内部是维护了一个 1KB 的字符数组的,写数据的时候会先写入到内部的字符数组中,如果需要把数据真正写到硬盘上,需要调用 flush 或 close 方法。
  2. 如果目标文件不存在,会自动创建目标文件。
  3. 如果在原有的文件上追加数据,需要使用 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。

    • 使用指定的编码将写入的字符编码为字节。
    • 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

作用:

  1. 如果目前所获取到的是一个字节流,且需要转换成字符流使用,这时就可以使用转换流。
  2. 使用转换流可以指定编码表进行读写文件(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

回到顶部