IO流

2019-07-30

IO操作

File类是在整个java.io包中唯一一个与文件本身操作有关的类,文件本身操作指的是文件的创建、删除、重命名等。但是如果要进行File类操作那么必须设置好要操作的文件或文件夹的路径,使用如下构造方法:

·构造方法:public File(String pathname),传入完整路径
·构造方法:public File(String parent,String child),传入父路径和子路径

基本的文件操作:

·创建新的文件:public boolean createNewFile() throws IOException
·删除文件:public boolean delete()
·判断文件是否存在:public boolean exists()
·找到父路径:public File getParentFile()
·创建目录:public boolean mkdirs()
·判断路径是否是文件:public boolean isFile()
·判断路径是否是文件夹:public boolean isDirectory()
·最后一次修改日期:public long lastModified()
·取得文件大小:public long length()
·修改文件名称:public boolean renameTo(File dest)

如果说现在给定的路径是一个文件夹,那么如果是文件夹则里面应该包含有许多的文件或子文件夹,那么现在就可以利用以下的方法列出目录之中的所有内容:

·列出目录内容:public File[] listFiles(),返回的是一个对象数组
字节流与字符流

使用File类只能够实现文件本身的操作,但是与文件内容的操作无关,如果要想进行文件内容的操作则可以使用一下两组流完成:

·字节流:InputStreamOutputStream;
·字符流:ReaderWriter;

不管使用何种流,基本的操作流程是一样的,以文件操作为例:

·确定操作文件的路径;
·通过字节流或字符流的子类为字节流或字符流类对象实例化;
·进行输入、输出的操作;
·关闭流,流属于资源操作,资源操作完成一定要关闭。

字节输出流:OutputStream
Java.io.OutputStream是可以进行字节数据(byte)的输出,这个类的定义结构如下:

public abstract class OutputStream
extends Object
implements Closeable, Flushable

OutputStream类之中存在有三个write()方法:

·输出单个字节:public abstract void write(int b)throws IOException
·输出全部字节:public void write(byte[] b)throws IOException
·输出部分字节:public void write(byte[] b,int off,int len)throws IOException

但是OutputStream只是一个抽象类,所以如果要想取得本类的实例化对象,那么就必须利用子类进行实例化,操作进行文件操作,可以使用FileOutputStream子类:public class FilterOutputStreamextends OutputStream。这个类定义了两个构造方法:

·构造方法:public FileOutputStream(File file)throws FileNotFoundException,覆盖
·构造方法:public FileOutputStream(File file,boolean append)throws FileNotFoundException,追加

字节输入流:InputStream
使用OutputStream可以完成程序向文件的输出,而现在要通过程序读取文件内容,则必须采用Inptustream类完成,此类的定义如下:

public abstract class InputStream
extends Object
implements Closeable

InputStream 类中有三个read()方法:

·读取单个字节:public abstract int read()throws IOException

每次使用read()操作将读取一个字节数据,此返回的是数据,如果数据已经读取完了,则int返回-1。

·读取内容到字节数组:public int read(byte[] b)throws IOException
将内容读取到字节数组之中,返回读取的个数,如果读取完毕,则返回-1。
·读取内容到部分字节数组:public int read(byte[] b,int off,int len)throws IOException将指定长度的内容读取到字节数组之中,返回读取的个数,如果读取完毕,返回-1。

但是InputStream类属于抽象类,抽象类要实例化则使用它的子类,可以使用FileInputStream子类完成,此类只关心构造方法:
public FileInputStream(File file)throws FileNotFoundException

字符输出流:Writer

InputStreamOutputStream两个类是在JDK1.0的时候引入的,但是在JDK1.1之后为了方便又提供了一组字符操作流(WriterReader),字节输出流和字符输出流最大的区别在于,字节输出流是以byte类型为主的,而字符输出流是以char类型为主的,而且支持String的直接操作。
观察Writer类的继承结构:

public abstract class Writer
extends Object
implements Appendable, Closeable, Flushable

Writer类之中提供有一个最为重要的操作方法:

·输出字符串:public void write(String str)throws IOException
·输出字节数组:public void write(char[] cbuf)throws IOException

但是Writer是一个抽象类,如果要使用它进行文件操作必须使用FileWriter子类

字符输入流:Reader

Reader是负责数据读取的,此类定义如下:

public abstract class Reader
extends Object
implements Readable, Closeable

同时在这个类之中可以使用read()方法读取数据,但是没有可以直接返回String 类型的读取操作,可以利用字符数组:

·读取数据:public int read(char[] cbuf)throws IOException
两种读取的操作本质上讲区别不大,只是字符流操作的都是char/String,而字节流只是byte

字节流和字符流的区别

·字符流:当程序处理中文的时候,字符流是最方便的;
·字节流:当程序处理二进制数据(图片、音乐、电影)或者进行网络传输,或者保存到磁盘数据一定都是字节。

字节流在进行操作的时候是直接与操作终端进行交互,而字符流需要经过缓冲区的处理后才可以进行操作,以OutputStreamWriter两个类输出文件为例,OutputStream输出的最后可以不关闭输出流,但是如果是Writer类输出如果没有关闭,那么保存在缓冲之中的数据将无法输出,或者强制性刷新缓冲区。
所谓的缓存实际上是一块内存,当数据读取进来之后会进入到此内存区域之中进行处理,所以才可以更好的处理中文,在进行选择的时候大部分情况都以字节流为主。
转换流
现在既然存在有字节流和字符流,那么这两种流之间也可以相互转换,主要使用两个类:InputStreamReaderOutputStreamWriter。这两个类的继承结构和构造方法如下:

InputStreamReaderpublic class InputStreamReader extends Reader
public InputStreamReader(InputStream in)
InputStreamReaderReader的子类,所以InputStreamReader类对象可以自动转型为Reader类实例
OutputStreamWriterpublic class OutputStreamWriter extends Writer
public OutputStreamWriter(OutputStream out)
OutputStreamWriterWriter的子类,所以OutputStreamWriter类对象可以自动转型为Writer类实例

FileInputStream:java.lang.Object
    				 java.io.InputStream
						java.io.FileInputStream
FileOutputStream:java.lang.Object
                     java.io.OutputStream
                        java.io.FilterOutputStream
FileReader: java.lang.Object
                java.io.Reader
                    java.io.InputStreamReader
                      java.io.FileReader
FileWriter: java.lang.Object
                      java.io.Writer
                          java.io.OutputStreamWriter
                              java.io.FileWriter

通过继承关系可以清楚的发现,所有的字符流数据实际上都经过了转换。

文件拷贝程序

·由于拷贝的文件可能是文本也有可能是二进制数据,所以应该使用字节流。

·对于文件的拷贝操作有两种方式:
·方案一:将要拷贝文件的内容一次性全部读取到内存之中后进行输出
·方案二:采用边读边写的方式,读部分内容再输出部分内容

现在一定要采用第二个操作方案,因为如果读取的文件过大,是没有内存可以装下的。

package IO;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class FileCopyModel {
	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		//**************此部分为辅助单元**************
		if(args.length != 2) {//输入的参数不足2个
			System.out.println("命令语法错误!");
			System.exit(1);//退出程序
		}
		File inFile = new File(args[0]);//源文件路径
		if(!inFile.exists()) {//如果源文件不存在
			System.out.println("源文件不存在!");
			System.exit(1);//退出程序
		}
		//**************此部分为辅助单元**************
		File outFile = new File(args[1]);//目标文件
		if(!outFile.exists()) {//目录不存在
			outFile.getParentFile().mkdirs();//创建目录
		}
		InputStream input = new FileInputStream(inFile);//输入流
		OutputStream output = new FileOutputStream(outFile);//输出流
		int temp = 0;//接收每次读取的数据
		while((temp = input.read()) != -1) {//有内容读取
			output.write(temp);//输出内容
		}
		input.close();
		output.close();
		long end = System.currentTimeMillis();
		System.out.println("文件拷贝所花费的时间:" + (end-start));
	}
}

此时程序需要配置初始化参数,但是在Eclipse之中,初始化参数需要将程序先执行一次之后才可以配置。
此时一个基本的程序结构就实现完成了,但是本程序存在问题,如果是一个文件量较大的程序,那么以上的代码根本就不可能完成任务。因为此时的操作采用的是一个字节一个字节的读取,性能一定很差。

改进代码:

package IO;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class AlterFileCopyModel {
	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		//**************此部分为辅助单元**************
		if(args.length != 2) {//输入的参数不足2个
			System.out.println("命令语法错误!");
			System.exit(1);//退出程序
		}
		File inFile = new File(args[0]);//源文件路径
		if(!inFile.exists()) {//如果源文件不存在
			System.out.println("源文件不存在!");
			System.exit(1);//退出程序
		}
		//**************此部分为辅助单元**************
		File outFile = new File(args[1]);//目标文件
		if(!outFile.exists()) {//目录不存在
			outFile.getParentFile().mkdirs();//创建目录
		}
		byte data[] = new byte[1024];//每次读取1024个数据
		InputStream input = new FileInputStream(inFile);//输入流
		OutputStream output = new FileOutputStream(outFile);//输出流
		int temp = 0;//接收每次读取的数据
		while((temp = input.read(data)) != -1) {//有内容读取
			output.write(data, 0, temp);// 输出内容
		}
		input.close();
		output.close();
		long end = System.currentTimeMillis();
		System.out.println("文件拷贝所花费的时间:" + (end-start));
	}
}

内存操作流

在之前所使用的是文件操作流,可以发现在操作过程之中,都是以文件为终端进行输入、输出,若现在需要使用IO操作,但是又不希望产生文件,可以将操作终端修改为内存,使用内存操作流完成。
内存操作流共分为两类:

·字节流内存操作:ByteArrayInputStreamByteArrayOutputStream
·字符流内存操作:CharArrayReaderCharArrayWriter

ByteArrayInputStream:java.lang.Object
                        java.io.InputStream
                            java.io.ByteArrayInputStream

构造方法: public ByteArrayInputStream(byte[] buf)

ByteArrayOutputStream:java.lang.Object
                           java.io.OutputStream
                              java.io.ByteArrayOutputStream

构造方法:public ByteArrayOutputStream()

文件与内存操作的区别:

·文件操作流

输出:程序→OutputStream→文件
输入:程序←InputStream←文件

·内存操作流

输出:程序→ByteArrayInputStream→内存
输入: 程序←ByteArrayOutputStream←内存

打印流

为了解决OutputStream输出的困难,在Java.io包之中专门提供有打印流类:PrintStream(字节打印流)、PrintWriter(字符打印流)

PrintStream:java.lang.Object
                java.io.OutputStream
                    java.io.FilterOutputStream
                        java.io.PrintStream

构造方法: public PrintStream(OutputStream out)

System类对IO的支持
System类之中定义的三个常量:

·错误输出:public static final PrintStream err
·系统输出:public static final PrintStream out
·系统输入:public static final InputStream in

BufferedReader

如果要想进行中文的处理使用字符流是最方便的,那么在输入数据的时候不能按照字节输入,应该将所有输入的内容保存在一个缓冲区之中,而后一次性的从该缓冲区中读取数据,这样才能更好的避免掉中文输入问题,所以就必须使用BufferedReader类来实现键盘输入。
继承结构:

java.lang.Object
      java.io.Reader
          java.io.BufferedReader

构造方法:public BufferedReader(Reader in)

在此类之中还定义了一个读取一行数据的方法:

public String readLine()throws IOException

此方法返回的是String类型数据,那么就意味着可以向任意类型数据转换,可以使用正则进行验证。

package IO;

import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Buff_In {
	public static void main(String[] args) throws Exception {
		//System.in是InputStream类对象,而BufferedReader需要接收的是Reader类对象
		//InputStreamReader是Reader的子类,其类构造可以接收InputStream类对象
		BufferedReader buf = new BufferedReader(
				new InputStreamReader(System.in));
		System.out.print("请输入数据:");
		String msg = buf.readLine();
		System.out.println(msg);
		buf.close();
	}
}

Scanner

Java.util.Scanner

·构造方法:public Scanner(InputStream source)
·设置读取分割符:public Scanner useDelimiter(String pattern)
·判断是否有数据:public Boolean hasNextXxx()
·取数据:public 数据 nextXxx()
·如果由程序输出内容,那么使用打印流(PrintStreamPrintWriter
·如果程序输入数据使用Scanner(如果有时候Scanner不好使的时候用BufferedReader).

对象序列化

对象序列化指的是将保存在内存中的对象转化为二进制数据的形式,这样就可以将对象保存在文件中或者是进行网络传输。但是如果要想实现对象序列化有一个要求:对象所在的类一定要实现java.io.Serializable接口,此接口没有任何的方法,所以是一个标识接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值