非流式文件类--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();//从输入流读取一个字节的内容赋给n
while(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);//写1024
fos.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)
// 将指定字符添加到此 writer
Writer append(char c)
// 将指定字符序列添加到此 writer
Writer append(CharSequence csq)
// 将指定字符序列的子序列添加到此 writer.Appendable
Writer 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);//默认输出缓冲区大小8192
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")));
//使用输入流和输出流完成文件复制
int n;//中转站,比较小(水杯)
//读一个字节
n = bis.read();//从输入流读取一个字节的内容赋给n
while(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:字节流转字符流,它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造方法:
// 创建一个使用默认字符集的 InputStreamReader
InputStreamReader(InputStream in)
// 创建使用给定字符集的 InputStreamReader
InputStreamReader(InputStream in, Charset cs)
// 创建使用给定字符集解码器的 InputStreamReader
InputStreamReader(InputStream in, CharsetDecoder dec)
// 创建使用指定字符集的 InputStreamReader
InputStreamReader(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:字节流转字符流。
构造方法:
// 创建使用默认字符编码的 OutputStreamWriter
OutputStreamWriter(OutputStream out)
// 创建使用给定字符集的 OutputStreamWriter
OutputStreamWriter(OutputStream out, Charset cs)
// 创建使用给定字符集编码器的 OutputStreamWriter
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
// 创建使用指定字符集的 OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)
特有方法:
//返回此流使用的字符编码的名称
String getEncoding()
(3).FileReader、FileWriter
FileReader:InputStreamReader类的直接子类,用来读取字符文件的便捷类,使用默认字符编码。
FileWriter:OutputStreamWriter类的直接子类,用来写入字符文件的便捷类,使用默认字符编码。
性能测试和调优
之前说带缓冲区会快很多,到底是不是这样呢?
我们复制一个MP4文件来测试一下
不带缓冲的用例两秒,这对于一个IO操作来说显然太长了。
我们用带缓冲区的试一下:
可以看到,读取次数一样,时间少了很多。
但是,读取次数还是太多了,我们可以通过扩大byte数组的方式来减少读写次数。
很明显,速度进一步加快。
但是请注意:也不是数组越大越好,视情况而定。
我们确定了数组大小之后,我们还可以设置缓冲区的大小进一步优化时间。
因为我们是从缓冲区读数据,缓冲区从硬盘读数据,形成这个体系可以加快我们的速度。
实际中可以多次调整尝试,确定最优的方案
System类对IO的支持
![](https://i-blog.csdnimg.cn/blog_migrate/f806a881b9b16eb1a99cb26f731374ee.png)
针对一些频繁的设备交互,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总结完啦