小言_互联网的博客

Java的常用IO操作类及使用

350人阅读  评论(0)


IO流用来处理设备之间的数据传输。Java中IO的核心组成为:一个类(File),一个接口 (Serializable),四个抽象类(InputStream,OutputStream,Reader,Writer)。

File文件操作类

File类可以操作文件路径的指派,创建或删除文件,获取文件相关信息。并且它实现了Comparable接口。

File类的常用构造器与方法:

File file1 = new File("F:/saki.txt");
File file2 = new File(new File("F:/"), "saki.text");
boolean create = file2.createNewFile();
boolean exists = file2.exists();// 是否存在
boolean delete = file2.delete();

使用Java中提供的路径分隔符常量可以让程序更好的兼容不同的系统:

File file1 = new File("F:" + File.separator + "saki.txt");

必须在父目录存在的情况下才可以进行子文件操作。

File类操作目录的相关方法:

boolean mkdir = file.mkdir();// 创建单级目录.
boolean mkdirs = file.mkdirs();// 创建多级目录 (所有的父路径).
String parent = file.getParent();// 获取父路径信息.
File parentFile = file.getParentFile();// 获取父路径实例.

特定场合可以使用静态域提前确保目录的存在, 提升并发时的性能:

private static File file = new File("F:" + File.separator+ "test" + File.separator + "saki.txt");
static {
    if (!file.getParentFile().exists()) {
        file.getParentFile().mkdirs();
    }
}

File类获取文件信息的相关方法:

boolean canExecute = file.canExecute();// 是否可执行.
boolean canRead = file.canRead();// 是否可读.
boolean canWrite = file.canWrite();// 是否可写.
File absoluteFile = file.getAbsoluteFile();// 获取文件绝对路径的实例.
String name = file.getName();// 获取文件或目录名.
boolean directory = file.isDirectory();// 当前路径是否为目录.
boolean file2 = file.isFile();// 当前路径是否为文件.
long lastModified = file.lastModified();// 获取最后一次的修改日期.
long length = file.length();// 获取文件字节长度.

File类对象如果是一个目录,可以通过下列方法返回目录下所有子目录与文件:

String[] list = file.list();
File[] listFiles = file.listFiles();

renameTo()方法接受一个File类型参数,将当前文件更名。

File oldFile = new File("F:" + File.separator + "test.txt");
File newFile = new File("F:" + File.separator + "saki.txt");
oldFile.renameTo(newFile);

字节流

流(Stream)主要指的是数据的处理方式,以及目标的内容处理机制。所有的流都分为输入流和输出流,在java.io中针对于输入流和输出流又划分为两种类型:

  • 字节操作流:OutputStream(字节输出流),InputStream(字节输入流)。
  • 字符操作流:Write(字符输出流),Reader(字符输入流)。

OutputStream是一个抽象类,在JDK1.5版本实现了Closeable(在JDK1.7版本该接口成为了AutoCloseable的子类)和Flushable接口,这两个接口分别提供了close()和flush()方法。

OutputStream提供了三种输出方法:

  • write(int b):输出单个字节数据。
  • write(byte[] b):输出全部字节数组的数据。
  • write(byte[] b, int off, int len):输出部分字节数组的数据。

OutputStream的实现类java.io.FileOutputStream可以完成对文件的操作:

OutputStream out = new FileOutputStream(new File("F:" + File.separator + "saki9.txt"));// 会覆盖之前的文件, 文件不存在时自动创建文件
out.write("Hello world".getBytes());
out.close();
OutputStream appendOut = new FileOutputStream(new File("F:" + File.separator + "saki9.txt"), true);// 不覆盖, 会将内容追加至当前文件后, 文件不存在时自动创建文件
appendOut.write("Hello world".getBytes());
appendOut.write("\r\nHello world".getBytes(), 0, 8);// 将指定范围内的内容写入
appendOut.close();

由于只有写操作时为了防止过多的写入才会用到缓冲区和Flushable接口的清空操作,因此InputStream只实现了Closeable接口。

InputStream提供了以下读取方法:

  • int read():读取单个字节数据,如果已经没有数据了返回“-1”。
  • int read(byte[] b):将内容读取到字节数组中,返回读取个数,如果没有数据返回“-1”。
  • int read(byte[] b, int off, int len):读取部分内容到字节数组中。
  • byte[] readAllBytes():JDK1.9版本方法,返回全部的字节数据,易造成内存溢出。
  • int available():获取可用的长度。

InputStream的实现类FileInputStream的常用构造器和方法:

InputStream input = new FileInputStream(new File("F:" + File.separator + "saki9.txt"));// 需要确保文件存在
byte[] data = new byte[1024];
int len = input.read(data);
String strData = new String(data, 0, len);
input.close();

字符流

由于大部分情况下对于输出操作最方便的处理类型是字符串类型,所以为了简化输出操作,从JDK1.1开始又提供了字符输出流Writer。

Writer比OutputStream多实现了一个Appendable接口(在JDK1.5版本追加实现)并提供了针对CharSequence类型操作的append方法(这些方法在JDK1.5之前的Writer类中已有实现)。

以下是Writer的实现类FileWriter的操作示例:

Writer writer = new FileWriter(new File("F:" + File.separator + "saki9.txt"));// 会覆盖之前的文件, 文件不存在时自动创建文件
// Writer writer = new FileWriter(new File("F:" + File.separator + "saki9.txt"), true);// 不覆盖, 会将内容追加至当前文件后, 文件不存在时自动创建文件
writer.write("Hello world");// 写入
writer.append("\r\nHello Saki9");// 写入, 该方法接受CharSequence类型参数
writer.close();

字符输入类Reader除了Closeable,还实现了Readable接口,此接口与NIO有关。

Reader的实现类FileReader其操作方法与FileInputStream类似:

Reader in = new FileReader(new File("F:" + File.separator + "saki9.txt"));// 需要确保文件存在
char[] data = new char[1024];
int len = in.read(data);
String strData = new String(data, 0, len);
in.close();

实现了AutoCloseable接口的类都可以通过在try结构体中定义,实现自动关闭流。可以在结构体中定义多个流,使用分号分隔符:

try (Reader in = new FileReader(new File("F:" + File.separator + "saki9.txt"))) {
    char[] data = new char[1024];
    int len = in.read(data);
    String strData = new String(data, 0, len);
} catch (Exception e) {
    e.printStackTrace();
}

缓冲区中的数据保存直到缓冲区满后才写出,也可以使用flush方法将缓冲区中的数据强制写出或使用close()方法关闭流,关闭流之前,缓冲区数据将会被一次性写出。

缓冲流

缓冲流使用装饰器模式对字符流进行功能上的增强,并利用缓冲区提高字符流的读写效率。

BufferedWriter继承自Writer,可以接收一个Writer类型参数,重载版本额外接收一个int类型参数,int值表示指定缓冲区的大小。以下为BufferedWriter的操作范例:

BufferedWriter out = new BufferedWriter(new FileWriter(new File("F:" + File.separator + "saki.txt"), true));
// BufferedWriter out = new BufferedWriter(new FileWriter(new File("F:" + File.separator + "saki.txt"), true), 1024);
out.write("text");
out.newLine();// 换行
out.close();

BufferedReader继承自Reader,可以接受一个Reader类型参数,同样可以通过给重载版本构造器传入int参数指定缓冲区大小。BufferedReader的操作范例:

BufferedReader in = new BufferedReader(new FileReader(new File("F:" + File.separator + "saki.txt")));// 需要确保文件存在
String readLine = in.readLine();// 读取一行, 没有数据则返回null
in.close();

转换流

OutputStreamWriter和InputStreamReader转换流类方便的实现了字节流与字符流的转换处理。

OutputStreamWriter实现了Writer,并且构造方法接受OutputStream对象作为参数。
InputStreamReader实现了Reader,并且构造方法接受InputStream对象作为参数。

Writer out = new OutputStreamWriter(new FileOutputStream(new File("F:" + File.separator + "saki9.txt")));
Reader in = new InputStreamReader(new FileInputStream(new File("F:" + File.separator + "saki9.txt")));

内存操作流

java.io中对于内存操作流提供有两类支持:

  • 字节内存流:ByteArrayInputStream,ByteArrayOutputStream。它们直接继承自字节流。
  • 字符内存流:CharArrayReader,CharArrayWriter。

字节内存流的常用构造器和操作方法如下:

InputStream in = new ByteArrayInputStream("TEST".getBytes());// 创建内存输入流, 参数作为内存中的一段数据
byte[] data = new byte[1024];
in.read(data);// 读取内存中的数据
ByteArrayOutputStream out = new ByteArrayOutputStream();// 创建内存输出流
out.write(data);// 将数据通过输出流写入内存
System.out.println(out.toString());// 内存输出流提供了toString()方法打印内存中的数据
System.out.println(new String(out.toByteArray()));// toByteArray()方法可以获取内存中数据的byte数组

序列流

SequenceInputStream继承自InputStream,它可以将其他多个输入流的逻辑串联,形成一个单独的流。

SequenceInputStream的构造器可以接受一个包含多个字节输入流对象的枚举,重载版本可以接受两个字节输入流。以下为SequenceInputStream的操作范例:

InputStream in1 = new FileInputStream(new File("F:" + File.separator + "1.txt"));
InputStream in2 = new FileInputStream(new File("F:" + File.separator + "2.txt"));
SequenceInputStream in = new SequenceInputStream(in1, in2);// 需要确保所有输入流指向的文件都存在
byte[] data = new byte[1024];
in.read(data);
in.read(data);
in.close();

对象的序列化

ObjectOutputStream继承自OutputStream,它可以将实现了serializable接口的Object对象通过流使用文件将对象进行持久存储。

以下是ObjectOutputStream类的使用示例:

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("F:" + File.separator + "saki.object")));
out.writeObject(new A("lily", 18));// 传入的对象需要实现Serializable接口
out.close();

ObjectInputStream 继承自InputStream,它可以对使用ObjectOutputStream写入的基本数据和对象进行反序列化,示例:

ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("F:" + File.separator + "saki.object")));
A o1 = (A)in.readObject();

管道流

管道流主要应用在不同线程的通讯处理上。

java.io中如果想实现线程的通讯管道,可以使用以下两类:

  • PipedInputStream,该类直接实现InputStream。
  • PipedOutputStream,该类直接实现OutputStream。

管道流的实现范例如下:

class A implements Runnable {
	private PipedOutputStream out = new PipedOutputStream();
	@Override
	public void run() {
		try {
			// 将数据写入管道
			out.write("hello".getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public PipedOutputStream getOut() {
		return out;
	}
}
class B implements Runnable {
	private PipedInputStream in = new PipedInputStream();
	@Override
	public void run() {
		try {
			byte[] data = new byte[100];
			// 将数据从管道读出
			in.read(data);
			System.out.println("接收数据: " + new String(data));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public PipedInputStream getIn() {
		return in;
	}
}
public class Main {
	public static void main(String[] args) throws IOException {
		A a = new A();
		B b = new B();
		a.getOut().connect(b.getIn());// 连接管道流
		a.run();
		b.run();
		// print: "接收数据: hello"
	}
}

随机访问文件

如果需要读取文件中需要的数据,就可以使用RandomAccessFile类。该类同时支持内容的输入与输出两个操作方式。

实例RandomAccessFile需要传递一个File对象,和一个String类型参数,常用的参数有“rw”代表可读写,“r”代表只读。使用“rw”参数时,文件不存在则自动创建文件。使用“r”参数时,文件不存在则程序报错。

以下为RandomAccessFile类常用写入方法,seek表示将索引指向什么位置,之后的操作将以索引位为起点进行。此例中索引被指向文件字节末尾,因此之后的写入操作可看作为追加:

RandomAccessFile raf = new RandomAccessFile("F:/text.saki", "rw");
raf.seek(raf.length());
raf.write("saki9".getBytes());// 写入byte数组类型参数
raf.writeInt(13);// 除writeInt()方法外还有支持各种不同类型的写入方法
raf.close();

以下为RandomAccessFile类常用读取方法:

RandomAccessFile raf = new RandomAccessFile("F:/text.saki", "r");
byte[] name = new byte[10];
raf.skipBytes(14);// 索引向后移动n位
raf.read(name);// 从索引位读取数组长度的字节, 读取后索引将移动到读取内容的结束位置
int age = raf.readInt();// 从索引位读取指定类型数据, 此外还支持不同类型读取方法
raf.close();

打印流

为了更便捷的使用OutputStream,Java提供了采用装饰器设计模式设计的以下两个类:

  • 字节打印流PrintStream:继承自OutputStream的子类FilterOutputStream。并且它的构造器可以接受一个OutputStream参数。
  • 字符打印流PrintWriter:继承自Writer,它的构造器可以接受一个OutputStream,或者也可以接受一个Writer对象。

以下为打印流操作范例:

PrintStream ps = new PrintStream(new FileOutputStream(new File("F:" + File.separator + "test.txt")));
ps.println("saki9");// 在文件中写入数据
ps.println("lily");
ps.close();
PrintWriter pw = new PrintWriter(new FileWriter(new File("F:" + File.separator + "test.txt"), true));
pw.println("tony");// 在文件中追加数据
pw.close();

转载:https://blog.csdn.net/saki09/article/details/101631615
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场