非流式文件类--File类
从定义看,File类是Object的直接子类,同时它继承了Comparable接口可以进行数组的排序。
File类的操作包括文件的创建、删除、重命名、得到路径、创建时间等,以下是文件操作常用的函数。
File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
File类共提供了三个不同的构造函数,以不同的参数形式灵活地接收文件和目录名信息。
构造函数:
1)File (String pathname)
例:File f1=new File("FileTest1.txt"); //创建文件对象f1,f1所指的文件是在当前目录下创建的FileTest1.txt
2)File (String parent , String child)
例:File f2=new File(“D:\\dir1","FileTest2.txt") ;// 注意:D:\\dir1目录事先必须存在,否则异常
3)File (File parent , String child)
例:File f4=new File("\\dir3");
File f5=new File(f4,"FileTest5.txt"); //在如果 \\dir3目录不存在使用f4.mkdir()先创建
一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。
1)public boolean exists( ) 判断文件或目录是否存在
2)public boolean isFile( ) 判断是文件还是目录
3)public boolean isDirectory( ) 判断是文件还是目录
4)public String getName( ) 返回文件名或目录名
5)public String getPath( ) 返回文件或目录的路径。
6)public long length( ) 获取文件的长度
7)public String[ ] list ( ) 将目录中所有文件名保存在字符串数组中返回。
File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:
1) public boolean renameTo( File newFile ); 重命名文件
2) public void delete( ); 删除文件
3) public boolean mkdir( ); 创建目录
流简单概念介绍
在Java程序中,对于数据的输入/输出操作以"流" (stream) 方式进行;
J2SDK提供了各种各样的"流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。
Java的流类型一般位于java.io包中
流的方向:
输入流:数据源到程序(InputStream、Reader读进来)
输出流:程序到目的地(OutPutStream、Writer写出去)
处理数据单元:
字节流:按照字节读取数据(InputStream、OutputStream)
字符流:按照字符读取数据(Reader、Writer)
功能不同:
节点流:可以直接从数据源或目的地读写数据。
处理流(包装流):不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能.
节点流和处理流的关系:
节点流处于io操作的第一线,所有操作必须通过他们进行;
处理流可以对其他流进行处理(提高效率或操作灵活性).
字节流基类
1).InputStream
InputStream:字节输入流基类,抽象类是表示字节输入流的所有类的超类。
常用方法:// 从输入流中读取数据的下一个字节abstract int read()// 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中int read(byte[] b)// 将输入流中最多 len 个数据字节读入 byte 数组int read(byte[] b, int off, int len)// 跳过和丢弃此输入流中数据的 n个字节long skip(long n)// 关闭此输入流并释放与该流关联的所有系统资源void close()
2).OutputStream
OutputStream:字节输出流基类,抽象类是表示输出字节流的所有类的超类。
常用方法:// 将 b.length 个字节从指定的 byte 数组写入此输出流void write(byte[] b)// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流void write(byte[] b, int off, int len)// 将指定的字节写入此输出流abstract void write(int b)// 关闭此输出流并释放与此流有关的所有系统资源void close()// 刷新此输出流并强制写出所有缓冲的输出字节void flush()
字节流FileInputStream和FileOuputStream
介绍
1).FileInputStream
FileInputStream:字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。
构造方法:// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定FileInputStream(File file)// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定FileInputStream(String name)常用方法:覆盖和重写了父类的的常用方法。
2).FileOutputStream
FileOutputStream:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。
构造方法:// 创建一个向指定File对象表示的文件中写入数据的文件输出流FileOutputStream(File file)// 创建一个向指定File对象表示的文件中写入数据的文件输出流FileOutputStream(File file, boolean append)// 创建一个向具有指定名称的文件中写入数据的输出文件流FileOutputStream(String name)// 创建一个向具有指定name的文件中写入数据的输出文件流FileOutputStream(String name, boolean append)常用方法:覆盖和重写了父类的的常用方法。
文件复制
(熟悉操作):
/**
* 功能:文件复制
* 技能:FileInputStream和FileOuputStream
*
* 总结
* 如何创建流
* InputStream is = new FileInputStream(new File("e:/readme.txt"));
* OutputStream os = new FileOutputStream(new File("e:\\readme2.txt"));
*
*
* 流使用完毕一定要关闭
*
* 如何使用流
* n = is.read();
* os.write(n);
*
* 缺点:
* @author Administrator
*
*/
public class TestCopy1 {public static void main(String[] args) throws IOException {//创建一个输入流和输出流
// File file = new File("e:/readme.txt");
// InputStream is = new FileInputStream(file);InputStream is = new FileInputStream(new File("e:/readme.txt"));
// File file2 = new File("e:\readme2.txt");
// OutputStream os = new FileOutputStream(file2);OutputStream os = new FileOutputStream(new File("e:\\readme2.txt"));//使用输入流和输出流完成文件复制int n;//中转站,比较小(水杯)//读一个字节n = is.read();//从输入流读取一个字节的内容赋给nwhile(n != -1){//没有到达末尾//写一个字节os.write(n);//输出一个字节//System.out.print((char)n);//读一个字节n = is.read();} //关闭输入流和输出流is.close();os.close();}}
正式标准实现:(一次1024)
/**
* 功能:文件复制
* 技能:FileInputStream和FileOuputStream
*
* 总结
* 如何创建流
* InputStream is = new FileInputStream(new File("e:/readme.txt"));
* OutputStream os = new FileOutputStream(new File("e:\\readme2.txt"));
*
*
* 流使用完毕一定要关闭
*
* 如何使用流
* n = is.read();
* os.write(n);
*
* 缺点:中转站太小
*
* @author Administrator
*
*/
public class TestCopy2 {public static void main(String[] args) throws IOException {//创建输入流和输出流InputStream fis = new FileInputStream("e:/JDK_API_1_6_zh_CN.CHM");OutputStream fos = new FileOutputStream("e:/JDK_API_1_6_zh_CN2.CHM");//使用输入流和输出流byte [] buf = new byte[1024];//读一次int len = fis.read(buf);//将源文件的内容写入到buf中,返回真实读取的字节数while(len != -1){//写一次//fos.write(buf);//写1024fos.write(buf, 0, len);//读一次len = fis.read(buf);}//关闭输入流和输出流fis.close();fos.close();}}
字符流Reader和Writer
字符流基类
1).Reader
Reader:读取字符流的抽象类.
常用方法:// 读取单个字符int read()// 将字符读入数组int read(char[] cbuf)// 将字符读入数组的某一部分abstract int read(char[] cbuf, int off, int len)// 跳过字符long skip(long n)// 关闭该流并释放与之关联的所有资源abstract void close()
2).Writer
Writer:写入字符流的抽象类.
常用方法:// 写入字符数组void write(char[] cbuf)// 写入字符数组的某一部分abstract void write(char[] cbuf, int off, int len)// 写入单个字符void write(int c)// 写入字符串void write(String str)// 写入字符串的某一部分void write(String str, int off, int len)// 将指定字符添加到此 writerWriter append(char c)// 将指定字符序列添加到此 writerWriter append(CharSequence csq)// 将指定字符序列的子序列添加到此 writer.AppendableWriter append(CharSequence csq, int start, int end)// 关闭此流,但要先刷新它abstract void close()// 刷新该流的缓冲abstract void flush()
文件复制:
熟悉操作
/**
*
* 1.字节流可以读写任何文件(文本文件、二进制文件(音频视频图片 chm))
* 字符流只可以读写文本文件(word不是文本文件)
* 但是字符串处理非英文字符文本文件非常方便
*
* 2.其实只有字节流,没有字符流
* 字符流底层使用的还是字节流
* Java在字节流基础上提供了字符流,给编程带来便利
*
* 3.字符流如何是英文字符还是中文字符
* 英文占一个字节,最高位是0 0111 0011
* 中文占两个字节,最高位是1 1011 1011 1001 1101
*
* 4.缺陷:没有进行异常处理
*
*
* @author Administrator
*
*/
public class TestCopy1 {public static void main(String[] args) throws IOException {//创建输入流和输出流Reader fr = new FileReader(new File("e:/readme.txt"));Writer fw = new FileWriter(new File("e:\\readme2.txt"));//默认是false 覆盖//Writer fw = new FileWriter(new File("e:\\readme2.txt"), true);//使用输入流和输出流
// //读一个字符
// int ch = fr.read(); //中转站是一个字符
// while(ch !=-1){
// //写一个字符
// fw.write(ch);
// //输出
// System.out.println((char)ch);
// //读一个字符
// ch = fr.read();
// } char cbuf [] = new char[1024];//读一次int len = fr.read(cbuf);//将读取的内容放入cbuf数组,返回的是真正读取的字符个数while(len != -1){//写一次//fw.write(cbuf);fw.write(cbuf, 0, len);//读一次len = fr.read(cbuf); } //关闭输入流和输出流fr.close();fw.close();}}
加上缺陷处理完整版:
/**
*
* 1.字节流可以读写任何文件(文本文件、二进制文件(音频视频图片 chm))
* 字符流只可以读写文本文件(word不是文本文件)
* 但是字符串处理非英文字符文本文件非常方便
*
* 2.其实只有字节流,没有字符流
* 字符流底层使用的还是字节流
* Java在字节流基础上提供了字符流,给编程带来便利
*
* 3.字符流如何是英文字符还是中文字符
* 英文占一个字节,最高位是0 0111 0011
* 中文占两个字节,最高位是1 1011 1011 1001 1101
*
* 4.缺陷:没有进行异常处理
*
*
* @author Administrator
*
*/
public class TestCopy2 {public static void main(String[] args){Reader fr = null;Writer fw = null;try {//创建输入流和输出流fr = new FileReader(new File("e:/readme.txt"));fw = new FileWriter(new File("e:\\readme2.txt"));//默认是false 覆盖char cbuf [] = new char[1024];//读一次int len = fr.read(cbuf);//将读取的内容放入cbuf数组,返回的是真正读取的字符个数while(len != -1){//写一次//fw.write(cbuf);fw.write(cbuf, 0, len);//读一次len = fr.read(cbuf); }} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally{//关闭输入流和输出流try {if(fr != null){fr.close();} } catch (IOException e) {e.printStackTrace();}try {if(fw != null){fw.close();} } catch (IOException e) {e.printStackTrace();}}}}
缓冲字节流BufferedInputStream和BufferedOuputStream
介绍
BufferedInputStream
字节缓冲输入流,提高了读取效率。
构造方法:// 创建一个 BufferedInputStream并保存其参数,即输入流in,以便将来使用。BufferedInputStream(InputStream in)// 创建具有指定缓冲区大小的 BufferedInputStream并保存其参数,即输入流in以便将来使用BufferedInputStream(InputStream in, int size)
.BufferedOutputStream
字节缓冲输出流,提高了写出效率。
构造方法:// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流BufferedOutputStream(OutputStream out)// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流BufferedOutputStream(OutputStream out, int size)常用方法:// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流void write(byte[] b, int off, int len)// 将指定的字节写入此缓冲的输出流void write(int b)// 刷新此缓冲的输出流void flush()
文件复制
/**
* 功能:文件复制
* 技能:BufferedInputStream和BufferedOuputStream
*
*
* 1.节点流和处理流
* 节点流 FileInputStream FileOutputStream
* 处理流 BufferedInputStream BufferedOutputStream
*
* 2.处理流的好处
* 好处1:提供了性能
*
*
* 3.如何创建处理流
* BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("e:/JDK_API_1_6_zh_CN.CHM")));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("e:\\JDK_API_1_6_zh_CN2.CHM")));* 4.关闭流:只要关闭高层流即可,底层流可以不关闭
* 关闭高层流的会关闭底层流
*
*
* 5.何时将输出缓冲区的内容更新到文件中(刷新 flush)
*
* 1.缓冲区满了,自动刷新
* 2.关闭输出流时,会先刷新再关闭
* 3.不满的时候也可以手动刷新
* bos.flush();
*
*
* public void close() throws IOException {try {flush();//刷新缓冲区} catch (IOException ignored) {}out.close(); //关闭底层流}
*
* @author Administrator
*
*/
public class TestCopy1 {public static void main(String[] args) throws IOException {//创建一个输入流和输出流
// InputStream is = new FileInputStream(new File("e:/JDK_API_1_6_zh_CN.CHM"));
// OutputStream os = new FileOutputStream(new File("e:\\JDK_API_1_6_zh_CN2.CHM"));
// BufferedInputStream bis = new BufferedInputStream(is);//默认输入缓冲区大小8192
// BufferedOutputStream bos = new BufferedOutputStream(os);//默认输出缓冲区大小8192BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("e:/JDK_API_1_6_zh_CN.CHM")));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("e:\\JDK_API_1_6_zh_CN2.CHM")));//使用输入流和输出流完成文件复制int n;//中转站,比较小(水杯)//读一个字节n = bis.read();//从输入流读取一个字节的内容赋给nwhile(n != -1){//没有到达末尾//写一个字节bos.write(n);//读一个字节n = bis.read();} //关闭输入流和输出流bis.close();bos.close();}}
缓冲字符流BufferedReader和BufferedWriter
1).BufferedReader
BufferedReader:字符缓冲流,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
构造方法:// 创建一个使用默认大小输入缓冲区的缓冲字符输入流BufferedReader(Reader in)// 创建一个使用指定大小输入缓冲区的缓冲字符输入流BufferedReader(Reader in, int sz)特有方法:// 读取一个文本行String readLine()
2).BufferedWriter
BufferedWriter:字符缓冲流,将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
构造方法:// 创建一个使用默认大小输出缓冲区的缓冲字符输出流BufferedWriter(Writer out)// 创建一个使用给定大小输出缓冲区的新缓冲字符输出流BufferedWriter(Writer out, int sz)特有方法:// 写入一个行分隔符void newLine()
文件复制
/**
* 按行读取文件并复制
*
* 只要文本文件才有行的概念 字符流
* 提高速度:缓冲流
* BufferedReader和BufferedWriter
*
*
*
* 1.处理流的好处
* 1.提高性能
* 2.简化操作
*
* 2.readLine的实现原理
* 底层还是按照字符一个个读取, 由于采用了缓冲区,性能是提高
* 基本思路:* StringBuilder builder = new StringBuilder("");* ch = br.read();* while(读取的这个字符是换行符的时候){* builder.append(ch);* ch = br.read();* }* return builder.toString();
*
* 3.bw.newLine(); 不同的操作系统,换行符不同
* (1)在微软的MS-DOS和Windows中,使用"回车CR('\r')"和"换行LF('\n')"两个字符作为换行符;Windows系统里面,每行结尾是 回车+换行(CR+LF),即"\r\n";(2)Unix系统里,每行结尾只有 换行CR,即"\n";(3)Mac系统里,每行结尾是 回车CR 即'\r'。
*
* *
* @author Administrator
*
*/
public class TestCopy2 {public static void main(String[] args) throws IOException {//创建输入流和输出流
// Reader fr = new FileReader(new File("e:/java基础题目以及答案1.txt"));
// BufferedReader br = new BufferedReader(fr);
// Writer fw = new FileWriter(new File("e:/java基础题目以及答案2.txt"));
// BufferedWriter bw = new BufferedWriter(fw);BufferedReader br = new BufferedReader(new FileReader(new File("e:/java基础题目以及答案1.txt")));BufferedWriter bw = new BufferedWriter(new FileWriter(new File("e:/java基础题目以及答案2.txt")));//使用输入流和输出流//读一行String str = br.readLine();while(str != null){//写一行bw.write(str);bw.newLine();//换一行//读一行str = br.readLine();} //关闭输入流和输出流 br.close();bw.close();}}
字符转换流
何时使用转换流?
1. 当字节和字符之间有转换动作时;
2. 流操作的数据需要编码或解码时。
1).InputStreamReader
InputStreamReader:字节流转字符流,它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造方法:// 创建一个使用默认字符集的 InputStreamReaderInputStreamReader(InputStream in)// 创建使用给定字符集的 InputStreamReaderInputStreamReader(InputStream in, Charset cs)// 创建使用给定字符集解码器的 InputStreamReaderInputStreamReader(InputStream in, CharsetDecoder dec)// 创建使用指定字符集的 InputStreamReaderInputStreamReader(InputStream in, String charsetName)特有方法://返回此流使用的字符编码的名称 String getEncoding()
/**
*
*
* 功能:将从键盘输入的一行行数据复制到另外一个文件中
*
* 1.转换流
* InputStreamReader 将InputStream转换成Reader
* OutputStreamWriter 将OutputStream转换成Writer
* ReaderInputStream 这个真没有
* WriterOutputStream 这个也没有
*
*
* 2.InputStreamReader到底是个InputStream还是一个Reader
* Reader reader = new InputStreamReader(is);
*
* public class InputStreamReader extends Reader
*
* 3.转换流使用了一个设计模式:适配器(转换器)模式
*
* 手机耳机口(大口)------------(大头)转换头(小口)------ 耳机(小头)
*
* Reader(readLine()) ------------ (Reader)转换流InputStreamReader(InputStream) --------- InputStream(System.in)
* *
*
*
* @author Administrator
*
*/
public class TestCopy1 {public static void main(String[] args) throws IOException {//创建输入流和输出流//Reader reader = new FileReader(new File("e:/java基础题目以及答案1.txt"));
// InputStream is = System.in;
// Reader reader = new InputStreamReader(is);
// BufferedReader br = new BufferedReader(reader);Scanner input = new Scanner(System.in);BufferedWriter bw = new BufferedWriter(new FileWriter(new File("e:/java.txt")));//使用输入流和输出流//读一行// String str = br.readLine();String str = input.next();while(!"bye".equals(str)){ //"null"//写一行bw.write(str);bw.newLine();//换一行//读一行//str = br.readLine();str = input.next();} //关闭输入流和输出流 //br.close();input.close();bw.close();}}
2).OutputStreamWriter
OutputStreamWriter:字节流转字符流。
构造方法:// 创建使用默认字符编码的 OutputStreamWriterOutputStreamWriter(OutputStream out)// 创建使用给定字符集的 OutputStreamWriterOutputStreamWriter(OutputStream out, Charset cs)// 创建使用给定字符集编码器的 OutputStreamWriterOutputStreamWriter(OutputStream out, CharsetEncoder enc)// 创建使用指定字符集的 OutputStreamWriterOutputStreamWriter(OutputStream out, String charsetName)特有方法://返回此流使用的字符编码的名称 String getEncoding()
(3).FileReader、FileWriter
FileReader:InputStreamReader类的直接子类,用来读取字符文件的便捷类,使用默认字符编码。FileWriter:OutputStreamWriter类的直接子类,用来写入字符文件的便捷类,使用默认字符编码。
性能测试和调优
之前说带缓冲区会快很多,到底是不是这样呢?
我们复制一个MP4文件来测试一下
不带缓冲的用例两秒,这对于一个IO操作来说显然太长了。
我们用带缓冲区的试一下:
可以看到,读取次数一样,时间少了很多。
但是,读取次数还是太多了,我们可以通过扩大byte数组的方式来减少读写次数。
很明显,速度进一步加快。
但是请注意:也不是数组越大越好,视情况而定。
我们确定了数组大小之后,我们还可以设置缓冲区的大小进一步优化时间。
因为我们是从缓冲区读数据,缓冲区从硬盘读数据,形成这个体系可以加快我们的速度。
实际中可以多次调整尝试,确定最优的方案
System类对IO的支持
针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:
· System.in(标准输入),通常代表键盘输入。
· System.out(标准输出):通常写往显示器。
· System.err(标准错误输出):通常写往显示器。
PrintStream
/**
*
* System.out 是PrintStream类的一个实例
* public final static PrintStream out = null;
* Student stu = null;
*
* PrintStream 输出流 字节流 处理流
* 打印流只有输出流,没有输入流
*
*
* PrintStream类的方法println() 这个方法功能简直太强大了!!!
* 可以直接讲各种数据类型(基本数据类型、引用数据类型)直接写入到文件中,并且换行。太方便了,太强大了!!
* 不管什么类型,写入到文件中全部变成字符串
* 缺点1: 123#3.14#true#bjsxt 需要使用特殊的字符来区分各个内容,防止混淆
* 缺点2: 123#3.14#true======="123" "3.14" "true" 读出来之后都是字符串,还需要将字符串转换成真实类型
*
* DataInputStream和DataOutputStream
*
* @author Administrator
*
*/
public class TestPrintStream {public static void main(String[] args) throws FileNotFoundException {//PrintStream ps = System.out;PrintStream ps = new PrintStream(new FileOutputStream(new File("e:/bjsxt.txt")));ps.println(123);ps.println('A');ps.println(3.14);ps.println(true);ps.println("bjsxt");ps.println(new Date().toString());OutputStream os =new FileOutputStream(new File("e:/bjsxt.txt"));// os.write(一个字节);
// String datestr = new Date().toString();;
// byte [] buf = datestr.getBytes();
// os.write(buf);
// BufferedWriter bw;
// bw.newLine();ps.close();}public void method1(){PrintStream ps = System.out;ps.println(123);ps.println('A');ps.println(3.14);ps.println(true);ps.println("111");ps.println(new Date().toString());// System.out.println(123);
// System.out.println('A');
// System.out.println(3.14);
// System.out.println(true);
// System.out.println("111");
// System.out.println(new Date().toString());}}
PrintWriter
/**
*
* 装饰模式
*
* this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),false);
*
* 减少了子类的数量,是继承的一种替代方案
*
* @author Administrator
*
*/
public class TestPrintWriter {public static void main(String[] args) throws IOException {PrintWriter pw1 = new PrintWriter(new FileWriter("e:/bjsxt.txt"));PrintWriter pw2 = new PrintWriter(new FileOutputStream("e:/bjsxt.txt"));PrintWriter pw3 = new PrintWriter(new File("e:/bjsxt.txt"));PrintWriter pw = new PrintWriter("e:/bjsxt.txt");pw.println(123);pw.println('A');pw.println(3.14);pw.println(true);pw.println("1111t");pw.println(new Date().toString());pw.close();}}
ACM IO 快速读写
输出
第一种使用传统的System.out.println()方式输出。
public class Main {public static void main(String[] args) {long start = System.currentTimeMillis();for(int i=0;i<100000;i++)System.out.println(i);long end = System.currentTimeMillis();System.out.println("time="+(end-start)+"ms");}
}
time=3443ms
显然在ACM中会超时
第二种使用PrintWriter输出:
public class Main {public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) {long start = System.currentTimeMillis();for(int i=0;i<100000;i++)out.println(i);out.flush();long end = System.currentTimeMillis();System.out.println("time="+(end-start)+"ms");out.close();}
}
结果:
time=328ms
虽然每次输出的结果会有大致几十毫秒的偏差,但总体上来看,PrintWriter输出要比用System.out.println()输出快上10倍左右。这个结果就比较让人满意了。
输入
Scanner类读取文件(in.txt,里面有从一到一百万的的整数)
public class Main {public static void main(String[] args) throws IOException{Scanner sc = new Scanner(new FileInputStream("in.txt"));long start = System.currentTimeMillis();for(int i=1;i<=1000000;i++)sc.nextInt();long end = System.currentTimeMillis();System.out.println("time="+(end-start)+"ms");}
}
运行结果:
time=2930ms
大概3秒,实际上如果ACM中真有一百万的数据,若用Scanner读取,还没开始计算,就已经超时了。
用StreamTokenizer读取
public class Main {public static StreamTokenizer in;static {try{in = new StreamTokenizer(new BufferedReader(new InputStreamReader(new FileInputStream("in.txt"))));}catch (Exception e){e.printStackTrace();}}public static int nextInt() throws IOException{ in.nextToken(); return (int)in.nval; }public static void main(String[] args) throws IOException{long start = System.currentTimeMillis();for(int i=1;i<=1000000;i++)nextInt(); //这里仅读取,不输出long end = System.currentTimeMillis();System.out.println("time="+(end-start)+"ms");}
}
运行结果:
time=397ms
要注意的是,用StreamTokenizer读取字符串时,只能读取纯字母字符串,如果包含数字或者其他字符会返回null。这是用StreamTokenizer读取的缺点。但是用它读取数字时没有问题的。
总结一下:
如果数据量比较小,用Scanner是比较方便的
如果数据量很大的话,那么用StreamTokenizer 是一个很好的选择
最后是模板:
import java.io.*;public class Main {public static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in),32768));public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));public static double nextDouble() throws IOException{ in.nextToken(); return in.nval; }public static float nextFloat() throws IOException{ in.nextToken(); return (float)in.nval; }public static int nextInt() throws IOException{ in.nextToken(); return (int)in.nval; }public static String next() throws IOException{ in.nextToken(); return in.sval;}public static void main(String[] args) throws IOException{
// 获取输入while(in.nextToken()!=StreamTokenizer.TT_EOF){break;}int x = (int)in.nextToken(); //第一个数据应当通过nextToken()获取int y = nextInt();float f = nextFloat();double d = nextDouble();String str = next();// 输出out.println("abc");out.flush();out.close();}
}
至此,Java的IO总结完啦