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
类只能够实现文件本身的操作,但是与文件内容的操作无关,如果要想进行文件内容的操作则可以使用一下两组流完成:
·字节流:
InputStream
、OutputStream
;
·字符流:Reader
、Writer
;
不管使用何种流,基本的操作流程是一样的,以文件操作为例:
·确定操作文件的路径;
·通过字节流或字符流的子类为字节流或字符流类对象实例化;
·进行输入、输出的操作;
·关闭流,流属于资源操作,资源操作完成一定要关闭。
字节输出流: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
InputStream
和OutputStream
两个类是在JDK1.0
的时候引入的,但是在JDK1.1
之后为了方便又提供了一组字符操作流(Writer
、Reader
),字节输出流和字符输出流最大的区别在于,字节输出流是以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
。
字节流和字符流的区别
·字符流:当程序处理中文的时候,字符流是最方便的;
·字节流:当程序处理二进制数据(图片、音乐、电影)或者进行网络传输,或者保存到磁盘数据一定都是字节。
字节流在进行操作的时候是直接与操作终端进行交互,而字符流需要经过缓冲区的处理后才可以进行操作,以OutputStream
和Writer
两个类输出文件为例,OutputStream
输出的最后可以不关闭输出流,但是如果是Writer
类输出如果没有关闭,那么保存在缓冲之中的数据将无法输出,或者强制性刷新缓冲区。
所谓的缓存实际上是一块内存,当数据读取进来之后会进入到此内存区域之中进行处理,所以才可以更好的处理中文,在进行选择的时候大部分情况都以字节流为主。
转换流
现在既然存在有字节流和字符流,那么这两种流之间也可以相互转换,主要使用两个类:InputStreamReader
、OutputStreamWriter
。这两个类的继承结构和构造方法如下:
①InputStreamReader
:public class InputStreamReader extends Reader
public InputStreamReader(InputStream in)
InputStreamReader
是Reader
的子类,所以InputStreamReader
类对象可以自动转型为Reader
类实例
②OutputStreamWriter
:public class OutputStreamWriter extends Writer
public OutputStreamWriter(OutputStream out)
OutputStreamWriter
是Writer
的子类,所以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操作,但是又不希望产生文件,可以将操作终端修改为内存,使用内存操作流完成。
内存操作流共分为两类:
·字节流内存操作:
ByteArrayInputStream
、ByteArrayOutputStream
·字符流内存操作:CharArrayReader
、CharArrayWriter
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()
·如果由程序输出内容,那么使用打印流(PrintStream
或PrintWriter
)
·如果程序输入数据使用Scanner
(如果有时候Scanner
不好使的时候用BufferedReader
).
对象序列化
对象序列化指的是将保存在内存中的对象转化为二进制数据的形式,这样就可以将对象保存在文件中或者是进行网络传输。但是如果要想实现对象序列化有一个要求:对象所在的类一定要实现java.io.Serializable
接口,此接口没有任何的方法,所以是一个标识接口。