Java中I/O(输入/输出)的操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pan_junbiao/article/details/85071661

Java的I/O技术可以将数据保存到文本文件、二进制文件甚至是ZIP压缩文件中,以达到永久性保存数据的要求。

1、流概述

流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流两种。I/O(Input/Output)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。虽然I/O流经常与磁盘文件存取有关,但是程序的源和目的地也可以是键盘、鼠标、内存或显示器窗口等。

2、输入/输出流

Java语言定义了许多类专门负责各种方式的输入/输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流)或抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输入流)或抽象类Writer(字符输出流)的子类。

2.1 输入流

InputStream类是字节输入流的抽象类,是所有字节输入流的父类。该类中所有方法遇到错误时都会引发IOException异常。

InputStream类的具体层次结构如图所示:

Java中的字符是Unicode编码,是双字节的。InputStream是用来处理字节的,在处理字符文本时不是很方便。Java为字符文本的输入提供了专门一套单独的类Reader,但Reader类并不是InputStream类的替换者,只是在处理字符串时简化了编程。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。

Reader类的具体层次结构如下图所示:

2.2 输出流

OutputStream类是字节输入流的抽象类,此抽象类是表示输出字节流的所有类的超类。OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常。

OutputStream类的具体层次如图所示:

Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。

Writer类的层次结构如下图所示:

3、File类

File对象即可表示文件,也可表示目录,在程序中一个File对象可以代表一个文件或目录。利用它可用来对文件或目录及其属性进行基本操作。

3.1 文件的创建与删除

(1)引入File类。

import java.io.File;

(2)构建一个文件对象,通用以下3种构造方法来创建文件对象。

File(String pathname)

File(String parent , String child)

File(File f , String child)

示例:在项目中创建类FileTest,在主方法中判断文件是否存在,如果该文件存在则将其删除,不存在则创建该文件。

import java.io.*;

public class FileTest
{
	// 创建类FileTest
	public static void main(String[] args)
	{
		// 创建文件对象
		File file = new File("word.txt");
		if (file.exists())
		{
			// 如果该文件存在
			file.delete(); // 将文件删除
			System.out.println("文件已删除"); // 输出的提示信息
		} else
		{
			// 如果文件不存在
			try
			{
				// try语句块捕捉可能出现的异常
				file.createNewFile(); // 创建该文件
				System.out.println("文件已创建"); // 输出的提示信息
			} catch (Exception e)
			{
				// catch处理该异常
				e.printStackTrace(); // 输出异常信息
			}
		}
	}
}

3.2 获取文件信息

File类提供了很多方法用于获取文件本身的一些信息,File类的常用方法如下表所示。

getName():获取文件的名称。

canRead():判断文件是否为可读的。

canWrite():判断文件是否可被写入。

exits():判断文件是否存在。

length():获取文件的长度(以字节为单位)。

getPath():获取文件路径。

getAbsolutePath():获取文件的绝对路径。

getParent():获取文件的父路径。

isFile():判断文件是否存在。

isDirectory():判断文件是否为一个目录。

isHidden():判断文件是否为隐藏文件。

lastModified():获取文件最后修改时间(返回值:long类型)。

示例:获取文件相关信息。

import java.io.*;

public class FileTest
{
	public static void main(String[] args)
	{
		File file = new File("word.txt"); // 创建文件对象
		if (file.exists())
		{ // 如果文件存在
			String name = file.getName(); // 获取文件名称
			long length = file.length(); // 获取文件长度
			String path = file.getPath();// 获取文件路径
			String absolutePath = file.getAbsolutePath();// 获取文件绝对路径
			boolean hidden = file.isHidden(); // 判断文件是否是隐藏文件
			System.out.println("文件名称:" + name); // 输出信息
			System.out.println("文件长度是:" + length);
			System.out.println("文件路径是:" + path);
			System.out.println("文件绝对路径是:" + absolutePath);
			System.out.println("该文件是隐藏文件吗?" + hidden);
		} else
		{ // 如果文件不存在
			System.out.println("该文件不存在"); // 输出信息
		}
	}
}

4、文件输入/输出流

4.1 FileInputStream与FileOutputStream类

FileInputStream类与FileOutputStream类都是用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream类。该类继承自InputStream类。FileOutputStream类与FileInputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutoputStream类的子类。

示例:使用FileOutputStream类向文件中写入信息,然后通过FileInputStream类将文件中的数据读取到控制台上。

import java.io.*;

public class FileTest
{
	public static void main(String[] args)
	{
		// 创建文件对象
		File file = new File("word.txt");

		// 文件写操作
		try
		{
			// 创建FileOutputStream对象
			FileOutputStream out = new FileOutputStream(file);

			// 创建byte型数组
			byte[] msgBytes = "我有一只小毛驴,我从来也不骑".getBytes();

			// 将数组中的信息写入到文件中
			out.write(msgBytes);

			// 关闭流
			out.close();
		} catch (Exception e)
		{
			e.printStackTrace();
		}

		// 文件读操作
		try
		{
			// 创建FileInputStream类对象
			FileInputStream in = new FileInputStream(file);

			// 创建Byte数组
			byte[] byt = new byte[1024];

			// 从文件中读取信息
			int len = in.read(byt);

			// 关闭流
			in.close();

			// 将文件中的信息输出
			System.out.println("文件中的信息是:" + new String(byt, 0, len));

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}

说明:虽然Java在程序结束时自动关闭所有打开的流,但是当使用完流后,显示地关闭所有打开的流仍是一个号习惯。一个被打开的流有可能会用尽系统资源,这取决于平台和实现。如果没有将打开的流关闭,当另一个程序试图打开另一个流时,可能会得不到需要的资源。

4.2 FileReader类和FileWriter类

使用FileOutputStream类向文件中写入数据与使用FileInputStream类从文件中将内容读出来,存在一点不足,即这两个类都只提供了对字节或字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象。此时采用字符流Reader或Writer类即可避免这种现象。
FileReader、FileWriter字符流对应了FileInputStream、FileOutputStream类。FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭。

示例:使用FileWriter类向文件中写入信息,然后通过FileReader类将文件中的数据读取到控制台上。

import java.io.*;

public class FileTest
{
	public static void main(String[] args)
	{
		// 创建文件对象
		File file = new File("word.txt");

		// 文件写操作
		try
		{
			// 创建FileWriter对象
			FileWriter out = new FileWriter(file);

			// 创建字符串内容
			String msgStr = "我有一只小毛驴,我从来也不骑";

			// 将数组中的信息写入到文件中
			out.write(msgStr);

			// 关闭流
			out.close();
		} catch (Exception e)
		{
			e.printStackTrace();
		}

		// 文件读操作
		try
		{
			// 创建FileReader类对象
			FileReader in = new FileReader(file);

			// 创建char数组
			char[] charArray = new char[1024];

			// 从文件中读取信息
			int len = in.read(charArray);

			// 关闭流
			in.close();

			// 将文件中的信息输出
			System.out.println("文件中的信息是:" + new String(charArray, 0, len));

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}

5、带缓存的输入输出流

缓存是I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区,使得在流上执行skip()、mark()和reset()方法都成为可能。

5.1 BufferedInputStream类与BufferedOutputStream类

BufferedInputStream类可以对任何的InputStream类进行带缓存区的包装以达到性能的优化。BufferedInputStream类有两个构造方法:

BufferedInputStream(InputStream in)。

BufferedInputStream(InputStream in, int size)。

使用BufferedOutputStream类输出信息和往OutputStream输出信息完全一样,只不过BufferedOutputStream有一个flush()方法用来将缓存区的数据强制输出完。BufferedOutputStream类也有两个构造方法:

BufferedOutputStream(OutputStream out)。

BufferedOutputStream(OutputStream out, int size)。

注意:flush()方法就是用于即使在缓存区没有满的情况下,也将缓存区的内容强制写入到外设,习惯上称这个过程为刷新。flush()方法只对使用缓存区的OutputStream类的子类有效。当调用close()方法时,系统在关闭流之前,也会将缓存区中的信息刷新到磁盘文件中。

5.2 BufferedReader与BufferedWriter类

BufferedReader类与BufferedWriter类分别继承Reader类与Writer类。这两个类同样具有内部缓存机制,并可以以行为单位进行输入输出。

BufferedReader类常用方法:

read():读取单个字符。

readLine():读取一个文本行,并将其返回为字符串。若无数据可读,则返回null。

在使用BufferedWriter类的Write()方法时,数据并没有立刻被写入至输出流中,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流中,一定要调用flush()方法。

BufferedWriter类中的方法都是返回void,常用方法:

write(String s, int off, int len):写入字符串的某一部分。

flush() :刷新该流的缓存。

newLine():写入一个行分隔符。

示例:向指定的文件写入数据,并通过BufferedReader类将文件中的信息分行显示。

import java.io.*;

public class FileTest
{
	public static void main(String args[])
	{
		// 定义字符串数组
		String content[] = { "好久不见", "最近好吗", "常联系" };
		File file = new File("word.txt"); // 创建文件对象
		try
		{
			FileWriter fw = new FileWriter(file); // 创建FileWriter类对象
			// 创建BufferedWriter类对象
			BufferedWriter bufw = new BufferedWriter(fw);
			// 循环遍历数组
			for (int k = 0; k < content.length; k++)
			{
				bufw.write(content[k]); // 将字符串数组中元素写入到磁盘文件中
				bufw.newLine(); // 将数组中的单个元素以单行的形式写入文件
			}
			bufw.close(); // 将BufferedWriter流关闭
			fw.close(); // 将FileWriter流关闭
		} catch (Exception e)
		{ // 处理异常
			e.printStackTrace();
		}
		try
		{
			FileReader fr = new FileReader(file); // 创建FileReader类对象
			// 创建BufferedReader类对象
			BufferedReader bufr = new BufferedReader(fr);
			String s = null; // 创建字符串对象
			int i = 0; // 声明int型变量
			// 如果文件的文本行数不为null,则进入循环
			while ((s = bufr.readLine()) != null)
			{
				i++; // 将变量做自增运算
				System.out.println("第" + i + "行:" + s); // 输出文件数据
			}
			bufr.close(); // 将FileReader流关闭
			fr.close(); // 将FileReader流关闭
		} catch (Exception e)
		{ // 处理异常
			e.printStackTrace();
		}
	}
}

运行结果:

第1行:好久不见
第2行:最近好吗
第3行:常联系

6、数据输入输出流

数据输入输出流(DataInputStream类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型。也就是说,当读取一个数据时,不必再关心这个数值应当是什么字节。

6.1 利用数据流类DataInputStream类读二进制文件

(1)引用相关类

import java.io.FileInputStream;
import java.io.DataInputStream;

(2)构造一个数据输入流对象

FileInputStream fis = new FileInputStream("D:\\MyImage.jpg");
DataInputStream dis = new DataInputStream(fis);

(3)利用数据输入流类的方法读取二进制文件的数据。

dis.readInt();   // 读取出来的是整型
dis.readByte();  // 读取出来的数据是Byte类型

(4)关闭数据输入流

dis.close();  // 关闭数据输入流

6.2 利用数据流类DataOutputStream类写二进制文件

(1)引用相关类

import java.io.DataOutputStream;
import java.io.FileOutputStream;

(2)构造一个数据输出流对象

FileOutputStream outFile = new FileOutputStream("E:\\MyImage2.jpg");
DataOutputStream out = new DataOutputStream(outFile);

(3)利用数据输出流类的方法写二进制文件的数据

out.write(1);   //把数据写入二进制文件

(4)关闭数据输出流

out.close();

示例:将D盘下的MyImage.jpg文件复制到E盘下,并命名为MyImage2.jpg。

import java.io.FileInputStream;
import java.io.DataInputStream;

import java.io.DataOutputStream;
import java.io.FileOutputStream;

public class ReadAndWriteBinaryFile
{

	public static void main(String[] args)
	{
		try
		{
			FileInputStream fis = new FileInputStream("D:\\MyImage.jpg");
			DataInputStream dis = new DataInputStream(fis);

			FileOutputStream outFile = new FileOutputStream("E:\\MyImage2.jpg");
			DataOutputStream out = new DataOutputStream(outFile);

			int temp;
			while ((temp = dis.read()) != -1)
			{
				out.write(temp);
			}

			dis.close();
			out.close();

			System.out.println("文件复制成功");

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}

7、ZIP压缩输入/输出流

ZIP压缩管理文件(ZIP archive)是一种十分典型的文件压缩形式,使用它可以节省存储空间。关于ZIP压缩的I/O实现,在Java的内置类中提供了非常好用的相关类,所以其实实现方法非常简单。使用java.util.zip包的ZipInputStream类与ZipOutputStream类来实现文件的压缩/解压缩。利用ZipEntry、ZipInputStream和ZipOutputStream这3个Java类实现ZIP数据压缩方式的编程方法。

7.1 压缩文件

利用ZipOutputStream类对象,可将文件压缩为“.zip”文件。ZipOutputStream类的构造函数如下所示:

ZipOutputStream(OutputStream out);

ZipOutputStream类的常用方法:

putNextEntry(ZipEntry e):开始编写新的ZIP文件条目,并将流定位到条目数据的开头。 

write(byte[] b, int off, int len):将一个字节数组写入当前的ZIP条目数据。 

finish():完成编写ZIP输出流的内容,而不关闭底层流。 

setComment(String comment):设置ZIP文件注释。

示例:使用ZipOutputStream类对文件夹进行压缩。

import java.io.*;
import java.util.zip.*;

public class MyZip { // 创建类
	private void zip(String zipFileName, File inputFile) throws Exception {
		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
				zipFileName)); // 创建ZipOutputStream类对象
		zip(out, inputFile, ""); // 调用方法
		System.out.println("压缩中…"); // 输出信息
		out.close(); // 将流关闭
	}
	
	private void zip(ZipOutputStream out, File f, String base)
			throws Exception { // 方法重载
		if (f.isDirectory()) { // 测试此抽象路径名表示的文件是否是一个目录
			File[] fl = f.listFiles(); // 获取路径数组
			out.putNextEntry(new ZipEntry(base + "/")); // 写入此目录的entry
			base = base.length() == 0 ? "" : base + "/"; // 判断参数是否为空
			for (int i = 0; i < fl.length; i++) { // 循环遍历数组中文件
				zip(out, fl[i], base + fl[i]);
			}
		} else {
			out.putNextEntry(new ZipEntry(base)); // 创建新的进入点
			// 创建FileInputStream对象
			FileInputStream in = new FileInputStream(f);
			int b; // 定义int型变量
			System.out.println(base);
			while ((b = in.read()) != -1) { // 如果没有到达流的尾部
				out.write(b); // 将字节写入当前ZIP条目
			}
			in.close(); // 关闭流
		}
	}
	
	public static void main(String[] temp) { // 主方法
		MyZip book = new MyZip(); // 创建本例对象
		try {
			// 调用方法,参数为压缩后文件与要压缩文件
			book.zip("hello.zip", new File("src"));
			System.out.println("压缩完成"); // 输出信息
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

7.2 解压ZIP文件

ZipInputStream类可读取ZIP压缩格式的文件,包括对已压缩和未压缩条目的支持(entry)。ZipInputStream类的构造函数如下所示:

ZipInputStream(InputStream in)

ZipInputStream的常用方法:

read(byte[] b, int off, int len):从当前ZIP条目读取到字节数组。 

available():判断是否已读完目前entry所指定的数据。已读完成返回0,否则返回1。

closeEntry():关闭当前的ZIP条目,并定位流以读取下一个条目。 

skip(long n):跳过当前ZIP条目中指定的字节数。 

getNextEntry():读取下一个ZIP文件条目,并将流定位在条目数据的开头。 

createZipEntry(String name):为指定的条目名称创建一个新的 ZipEntry对象。

示例:使用ZipInputStream类对文件进行解压缩。

import java.io.*;
import java.util.zip.*;

public class Decompressing { // 创建文件
	public static void main(String[] temp) {
		ZipInputStream zin; // 创建ZipInputStream对象
		try { // try语句捕获可能发生的异常
			zin = new ZipInputStream(new FileInputStream("hello.zip"));
			// 实例化对象,指明要进行解压的文件
			ZipEntry entry = zin.getNextEntry(); // 获取下一个ZipEntry
			while (((entry = zin.getNextEntry()) != null)
					&& !entry.isDirectory()) {
				// 如果entry不为空,并不在同一目录下
				File file = new File("d:\\" + entry.getName()); // 获取文件目录
				System.out.println(file);
				if (!file.exists()) { // 如果该文件不存在
					file.mkdirs();// 创建文件所在文件夹
					file.createNewFile(); // 创建文件
				}
				zin.closeEntry(); // 关闭当前entry
				System.out.println(entry.getName() + "解压成功");
			}
			zin.close(); // 关闭流
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

总结:

1、流是指一连串流动的字符,是以先进先出的方式发送信息的通道。程序和数据源之间是通过流联系起来的。

2、流可以分为输入流和输出流,也可以分为字节流和字符流。

3、File类用于访问文件或目录的属性。

4、FileInputStream类和FileOutputStream类以字节流的方式读写文本文件。

5、BufferedReader类和BufferedWriter类以字符流的方式读写文本文件,而且效率更高。

6、DataInputStream类和DataOutputStream类可用于读写二进制文件。

7、ZipInputStream类和ZipOutputStream类可用于文件的压缩和解压缩。

猜你喜欢

转载自blog.csdn.net/pan_junbiao/article/details/85071661