[Java] I/O流

>>  http://www.jb51.net/article/44684.htm

>>  http://blog.csdn.net/ilibaba/article/details/3955799

>>  http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html

IO流的分类
1、根据流的数据对象来分:
高端流:所有的内存中的流都是高端流,比如:InputStreamReader  
低端流:所有的外界设备中的流都是低端流,比如InputStream,OutputStream 
如何区分:所有的流对象的后缀中包含Reader或者Writer的都是高端流,反之,则基本上为低端流,不过也有例外,比如PrintStream就是高端流


2、根据数据的流向来分:
输出流:是用来写数据的,是由程序(内存)--->外界设备
输入流:是用来读数据的,是由外界设备--->程序(内存)
如何区分:一般来说输入流带有Input,输出流带有Output 


3、根据流数据的格式来分:
字节流:处理声音或者图片等二进制的数据的流,比如InputStream 
字符流:处理文本数据(如txt文件)的流,比如InputStreamReader  
如何区分:可用高低端流来区分,所有的低端流都是字节流,所有的高端流都是字符流


4、根据流数据的包装过程来分:
原始流:在实例化流的对象的过程中,不需要传入另外一个流作为自己构造方法的参数的流,称之为原始流。
包装流:在实例化流的对象的过程中,需要传入另外一个流作为自己构造方法发参数的流,称之为包装流。
如何区分:所以的低端流都是原始流,所以的高端流都是包装流


IO流对象的继承关系(如下图):

 

Java IO 的一般使用原则 :  

一、按数据来源(去向)分类:

1 、是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )

2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )

3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )

4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )

5 、网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )

二、按是否格式化输出分:

1 、要格式化输出: PrintStream, PrintWriter

三、按是否要缓冲分:

1 、要缓冲: BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 )

四、按数据格式分:

1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类

2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类

五、按输入输出分:

1 、输入: Reader, InputStream 类型的子类

2 、输出: Writer, OutputStream 类型的子类

六、特殊需要:

1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter

2 、对象输入输出: ObjectInputStream, ObjectOutputStream

3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter

4 、合并输入: SequenceInputStream

5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):

首先,考虑最原始的数据格式是什么: 原则四

第二,是输入还是输出:原则五

第三,是否需要转换流:原则六第 1 点

第四,数据来源(去向)是什么:原则一

第五,是否要缓冲:原则三 (特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特殊的输入或输出方法)

第六,是否要格式化输出:原则二



【案例1】创建一个新文件
import java.io.*;
class hello{
    public static void main(String[] args) {
        File f=new File("D:\hello.txt");
        try{
            f.createNewFile();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
【运行结果】:
程序运行之后,在d盘下会有一个名字为hello.txt的文件。

【案例2】File类的两个常量
import java.io.*; class hello{ public static void main(String[] args) { System.out.println(File.separator); System.out.println(File.pathSeparator); } } 【运行结果】: ; 此处多说几句:有些同学可能认为,我直接在windows下使用进行分割不行吗?当然是可以的。但是在linux下就不是了。
所以,要想使得我们的代码跨平台,更加健壮,所以,大家都采用这两个常量吧,其实也多写不了几行。呵呵、

现在我们使用File类中的常量改写上面的代码:
import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); try{ f.createNewFile(); }catch (Exception e) { e.printStackTrace(); } } } 你看,没有多写多少吧,呵呵。所以建议使用File类中的常量。 删除一个文件 import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); if(f.exists()){ f.delete(); }else{ System.out.println("文件不存在"); } } }
创建一个文件夹
import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator+"hello"; File f=new File(fileName); f.mkdir(); } } 【运行结果】:
D盘下多了一个hello文件夹 列出指定目录的全部文件(包括隐藏文件):
/** * 使用list列出指定目录的全部文件 * */ import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator; File f=new File(fileName); String[] str=f.list(); for (int i = 0; i < str.length; i++) { System.out.println(str[i]); } } } 【运行结果】: $RECYCLE.BIN 360 360Downloads 360Rec 360SoftMove Config.Msi da Downloads DriversBackup eclipse java web整合开发和项目实战 Lenovo MSOCache Program Program Files python RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19} System Volume Information Tomcat6 var vod_cache_data (你的运行结果应该和这个不一样的,呵呵) 但是使用list返回的是String数组,。而且列出的不是完整路径,如果想列出完整路径的话,需要使用listFiles.他返回的是File的数组
列出指定目录的全部文件(包括隐藏文件):
/** * 使用listFiles列出指定目录的全部文件 * listFiles输出的是完整路径 * */ import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator; File f=new File(fileName); File[] str=f.listFiles(); for (int i = 0; i < str.length; i++) { System.out.println(str[i]); } } } 【运行结果】: D:$RECYCLE.BIN D:360 D:360Downloads D:360Rec D:360SoftMove D:Config.Msi D:da D:Downloads D:DriversBackup D:eclipse D:java web整合开发和项目实战 D:Lenovo D:MSOCache D:Program D:Program Files D:python D:RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19} D:System Volume Information D:Tomcat6 D:var D:vod_cache_data D:新建文件夹 通过比较可以指定,使用listFiles更加方便、 判断一个指定的路径是否为目录 /** * 使用isDirectory判断一个指定的路径是否为目录 * */ import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator; File f=new File(fileName); if(f.isDirectory()){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 【运行结果】:YES 搜索指定目录的全部内容 /** * 列出指定目录的全部内容 * */ import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator; File f=new File(fileName); print(f); } public static void print(File f){ if(f!=null){ if(f.isDirectory()){ File[] fileArray=f.listFiles(); if(fileArray!=null){ for (int i = 0; i < fileArray.length; i++) { //递归调用 print(fileArray[i]); } } } else{ System.out.println(f); } } } } 【运行结果】: D:Tomcat6workCatalinalocalhost evelorgapachejspframepagesweb4welcome_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejsphelp_005fhome_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejsphelp_005fhome_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejsphome_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejsphome_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejspindex_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejspindex_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejsplogin_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejsplogin_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejspmodify_005fuser_005finfo_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejspmodify_005fuser_005finfo_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejsp egister_005fnotify_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejsp egister_005fnotify_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejspsign_005fup_jsp.class D:Tomcat6workCatalinalocalhost evelorgapachejspsign_005fup_jsp.java D:Tomcat6workCatalinalocalhost evelorgapachejsp ransit_jsp.class …… 【使用RandomAccessFile写入文件】 /** * 使用RandomAccessFile写入文件 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); RandomAccessFile demo=new RandomAccessFile(f,"rw"); demo.writeBytes("asdsad"); demo.writeInt(12); demo.writeBoolean(true); demo.writeChar('A'); demo.writeFloat(1.21f); demo.writeDouble(12.123); demo.close(); } } 如果你此时打开hello。txt查看的话,会发现那是乱码。 字节流 【向文件中写入字符串】 /** * 字节流 * 向文件中写入字符串 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); OutputStream out =new FileOutputStream(f); String str="你好"; byte[] b=str.getBytes(); out.write(b); out.close(); } } 查看hello.txt会看到“你好”

当然也可以一个字节一个字节的写。
/** * 字节流 * 向文件中一个字节一个字节的写入字符串 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); OutputStream out =new FileOutputStream(f); String str="你好"; byte[] b=str.getBytes(); for (int i = 0; i < b.length; i++) { out.write(b[i]); } out.close(); } } 结果还是:“你好” 向文件中追加新内容: /** * 字节流 * 向文件中追加新内容: * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); OutputStream out =new FileOutputStream(f,true); String str="Rollen"; //String str=" Rollen"; 可以换行 byte[] b=str.getBytes(); for (int i = 0; i < b.length; i++) { out.write(b[i]); } out.close(); } } 【运行结果】: 你好Rollen 【读取文件内容】 /** * 字节流 * 读文件内容 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1024]; in.read(b); in.close(); System.out.println(new String(b)); } } 【运行结果】 你好Rollen Rollen_
但是这个例子读取出来会有大量的空格,我们可以利用in.read(b);的返回值来设计程序。如下:
/** * 字节流 * 读文件内容 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1024]; int len=in.read(b); in.close(); System.out.println("读入长度为:"+len); System.out.println(new String(b,0,len)); } } 【运行结果】: 读入长度为:18 你好Rollen Rollen 读者观察上面的例子可以看出,我们预先申请了一个指定大小的空间,但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样干: /** * 字节流 * 读文件内容,节省空间 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[(int)f.length()]; in.read(b); System.out.println("文件长度为:"+f.length()); in.close(); System.out.println(new String(b)); } } 文件长度为:18 你好Rollen Rollen 将上面的例子改为一个一个读: /** * 字节流 * 读文件内容,节省空间 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[(int)f.length()]; for (int i = 0; i < b.length; i++) { b[i]=(byte)in.read(); } in.close(); System.out.println(new String(b)); } } 输出的结果和上面的一样。 细心的读者可能会发现,上面的几个例子都是在知道文件的内容多大,然后才展开的,有时候我们不知道文件有多大,这种情况下,我们需要判断是否独到文件的末尾。 /** * 字节流 *读文件 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1024]; int count =0; int temp=0; while((temp=in.read())!=(-1)){ b[count++]=(byte)temp; } in.close(); System.out.println(new String(b)); } } 【运行结果】 你好Rollen Rollen_ 提醒一下,当独到文件末尾的时候会返回-1.正常情况下是不会返回-1的 字符流 【向文件中写入数据】 现在我们使用字符流 /** * 字符流 * 写入数据 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); Writer out =new FileWriter(f); String str="hello"; out.write(str); out.close(); } } 当你打开hello。txt的时候,会看到hello 其实这个例子上之前的例子没什么区别,只是你可以直接输入字符串,而不需要你将字符串转化为字节数组。 当你如果想问文件中追加内容的时候,可以使用将上面的声明out的哪一行换为: Writer out =new FileWriter(f,true); 这样,当你运行程序的时候,会发现文件内容变为: hellohello如果想在文件中换行的话,需要使用“ ” 比如将str变为String str=" hello"; 这样文件追加的str的内容就会换行了。 从文件中读内容: /** * 字符流 * 从文件中读出内容 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); char[] ch=new char[100]; Reader read=new FileReader(f); int count=read.read(ch); read.close(); System.out.println("读入的长度为:"+count); System.out.println("内容为"+new String(ch,0,count)); } } 【运行结果】: 读入的长度为:17 内容为hellohello hello 当然最好采用循环读取的方式,因为我们有时候不知道文件到底有多大。 /** * 字符流 * 从文件中读出内容 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); char[] ch=new char[100]; Reader read=new FileReader(f); int temp=0; int count=0; while((temp=read.read())!=(-1)){ ch[count++]=(char)temp; } read.close(); System.out.println("内容为"+new String(ch,0,count)); } } 运行结果: 内容为hellohello hello 关于字节流和字符流的区别 实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作的 时候下后是会用到缓冲区的,是通过缓冲区来操作文件的。 读者可以试着将上面的字节流和字符流的程序的最后一行关闭文件的代码注释掉,然后运行程序看看。
你就会发现使用字节流的话,文件中已经存在内容,但是使用字符流的时候,文件中还是没有内容的,这个时候就要刷新缓冲区。 使用字节流好还是字符流好呢? 答案是字节流。
首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。

文件的复制 其实DOS下就有一个文件复制功能,比如我们想把d盘下面的hello.txt文件复制到d盘下面的rollen.txt文件中,那么我们就可以使用下面的命令: copy d:hello.txt d: ollen.txt 运行之后你会在d盘中看见hello.txt.,并且两个文件的内容是一样的,(这是屁话) 下面我们使用程序来复制文件吧。 基本思路还是从一个文件中读入内容,边读边写入另一个文件,就是这么简单。 首先编写下面的代码:
/** * 文件的复制 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { if(args.length!=2){ System.out.println("命令行参数输入有误,请检查"); System.exit(1); } File file1=new File(args[0]); File file2=new File(args[1]); if(!file1.exists()){ System.out.println("被复制的文件不存在"); System.exit(1); } InputStream input=new FileInputStream(file1); OutputStream output=new FileOutputStream(file2); if((input!=null)&&(output!=null)){ int temp=0; while((temp=input.read())!=(-1)){ output.write(temp); } } input.close(); output.close(); } } 然后在命令行下面 javac hello.java java hello d:hello.txt d: ollen.txt 现在你就会在d盘看到rollen。txt了, OutputStreramWriter 和InputStreamReader类 整个IO类中除了字节流和字符流还包括字节和字符转换流。 OutputStreramWriter将输出的字符流转化为字节流 InputStreamReader将输入的字节流转换为字符流 但是不管如何操作,最后都是以字节的形式保存在文件中的。 将字节输出流转化为字符输出流 /** * 将字节输出流转化为字符输出流 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName= "d:"+File.separator+"hello.txt"; File file=new File(fileName); Writer out=new OutputStreamWriter(new FileOutputStream(file)); out.write("hello"); out.close(); } } 运行结果:文件中内容为:hello
将字节输入流变为字符输入流
/** * 将字节输入流变为字符输入流 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String fileName= "d:"+File.separator+"hello.txt"; File file=new File(fileName); Reader read=new InputStreamReader(new FileInputStream(file)); char[] b=new char[100]; int len=read.read(b); System.out.println(new String(b,0,len)); read.close(); } } 【运行结果】:hello
前面列举的输出输入都是以文件进行的,现在我们以内容为输出输入目的地,使用内存操作流 ByteArrayInputStream 主要将内容写入内容 ByteArrayOutputStream 主要将内容从内存输出
使用内存操作流将一个大写字母转化为小写字母
/** * 使用内存操作流将一个大写字母转化为小写字母 * */ import java.io.*; class hello{ public static void main(String[] args) throws IOException { String str="ROLLENHOLT"; ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes()); ByteArrayOutputStream output=new ByteArrayOutputStream(); int temp=0; while((temp=input.read())!=-1){ char ch=(char)temp; output.write(Character.toLowerCase(ch)); } String outStr=output.toString(); input.close(); output.close(); System.out.println(outStr); } } 【运行结果】: rollenholt
内容操作流一般使用来生成一些临时信息采用的,这样可以避免删除的麻烦。
管道流 管道流主要可以进行两个线程之间的通信。 PipedOutputStream 管道输出流 PipedInputStream 管道输入流 验证管道流
/** * 验证管道流 * */ import java.io.*; /** * 消息发送类 * */ class Send implements Runnable{ private PipedOutputStream out=null; public Send() { out=new PipedOutputStream(); } public PipedOutputStream getOut(){ return this.out; } public void run(){ String message="hello , Rollen"; try{ out.write(message.getBytes()); }catch (Exception e) { e.printStackTrace(); }try{ out.close(); }catch (Exception e) { e.printStackTrace(); } } } /** * 接受消息类 * */ class Recive implements Runnable{ private PipedInputStream input=null; public Recive(){ this.input=new PipedInputStream(); } public PipedInputStream getInput(){ return this.input; } public void run(){ byte[] b=new byte[1000]; int len=0; try{ len=this.input.read(b); }catch (Exception e) { e.printStackTrace(); }try{ input.close(); }catch (Exception e) { e.printStackTrace(); } System.out.println("接受的内容为 "+(new String(b,0,len))); } } /** * 测试类 * */ class hello{ public static void main(String[] args) throws IOException { Send send=new Send(); Recive recive=new Recive(); try{ //管道连接 send.getOut().connect(recive.getInput()); }catch (Exception e) { e.printStackTrace(); } new Thread(send).start(); new Thread(recive).start(); } } 【运行结果】: 接受的内容为 hello , Rollen

打印流
/** * 使用PrintStream进行输出 * */ import java.io.*; class hello { public static void main(String[] args) throws IOException { PrintStream print = new PrintStream(new FileOutputStream(new File("d:" + File.separator + "hello.txt"))); print.println(true); print.println("Rollen"); print.close(); } } 【运行结果】: true Rollen

当然也可以格式化输出
/** * 使用PrintStream进行输出 * 并进行格式化 * */ import java.io.*; class hello { public static void main(String[] args) throws IOException { PrintStream print = new PrintStream(new FileOutputStream(new File("d:" + File.separator + "hello.txt"))); String name="Rollen"; int age=20; print.printf("姓名:%s. 年龄:%d.",name,age); print.close(); } } 【运行结果】: 姓名:Rollen. 年龄:20. 使用OutputStream向屏幕上输出内容 /** * 使用OutputStream向屏幕上输出内容 * */ import java.io.*; class hello { public static void main(String[] args) throws IOException { OutputStream out=System.out; try{ out.write("hello".getBytes()); }catch (Exception e) { e.printStackTrace(); } try{ out.close(); }catch (Exception e) { e.printStackTrace(); } } } 【运行结果】: hello 输入输出重定向 import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** * 为System.out.println()重定向输出 * */ public class systemDemo{ public static void main(String[] args){ // 此刻直接输出到屏幕 System.out.println("hello"); File file = new File("d:" + File.separator + "hello.txt"); try{ System.setOut(new PrintStream(new FileOutputStream(file))); }catch(FileNotFoundException e){ e.printStackTrace(); } System.out.println("这些内容在文件中才能看到哦!"); } } 【运行结果】: eclipse的控制台输出的是hello。然后当我们查看d盘下面的hello.txt文件的时候,会在里面看到:这些内容在文件中才能看到哦!
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** * System.err重定向 这个例子也提示我们可以使用这种方法保存错误信息 * */ public class systemErr{ public static void main(String[] args){ File file = new File("d:" + File.separator + "hello.txt"); System.err.println("这些在控制台输出"); try{ System.setErr(new PrintStream(new FileOutputStream(file))); }catch(FileNotFoundException e){ e.printStackTrace(); } System.err.println("这些在文件中才能看到哦!"); } } 【运行结果】: 你会在eclipse的控制台看到红色的输出:“这些在控制台输出”,然后在d盘下面的hello.txt中会看到:这些在文件中才能看到哦!
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * System.in重定向 * */ public class systemIn{ public static void main(String[] args){ File file = new File("d:" + File.separator + "hello.txt"); if(!file.exists()){ return; }else{ try{ System.setIn(new FileInputStream(file)); }catch(FileNotFoundException e){ e.printStackTrace(); } byte[] bytes = new byte[1024]; int len = 0; try{ len = System.in.read(bytes); }catch(IOException e){ e.printStackTrace(); } System.out.println("读入的内容为:" + new String(bytes, 0, len)); } } } 【运行结果】: 前提是我的d盘下面的hello.txt中的内容是:“这些文件中的内容哦!”,然后运行程序,输出的结果为:读入的内容为:这些文件中的内容哦! BufferedReader的小例子 注意: BufferedReader只能接受字符流的缓冲区,因为每一个中文需要占据两个字节,所以需要将System.in这个字节输入流变为字符输入流,采用: BufferedReader buf = new BufferedReader(new InputStreamReader(System.in)); 下面给一个实例: import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * 使用缓冲区从键盘上读入内容 * */ public class BufferedReaderDemo{ public static void main(String[] args){ BufferedReader buf = new BufferedReader( new InputStreamReader(System.in)); String str = null; System.out.println("请输入内容"); try{ str = buf.readLine(); }catch(IOException e){ e.printStackTrace(); } System.out.println("你输入的内容是:" + str); } } 运行结果: 请输入内容 dasdas 你输入的内容是:dasdas Scanner类 其实我们比较常用的是采用Scanner类来进行数据输入,下面来给一个Scanner的例子吧 import java.util.Scanner; /** * Scanner的小例子,从键盘读数据 * */ public class ScannerDemo{ public static void main(String[] args){ Scanner sca = new Scanner(System.in); // 读一个整数 int temp = sca.nextInt(); System.out.println(temp); //读取浮点数 float flo=sca.nextFloat(); System.out.println(flo); //读取字符 //...等等的,都是一些太基础的,就不师范了。 } } 其实Scanner可以接受任何的输入流
下面给一个使用Scanner类从文件中读出内容
import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; /** * Scanner的小例子,从文件中读内容 * */ public class ScannerDemo{ public static void main(String[] args){ File file = new File("d:" + File.separator + "hello.txt"); Scanner sca = null; try{ sca = new Scanner(file); }catch(FileNotFoundException e){ e.printStackTrace(); } String str = sca.next(); System.out.println("从文件中读取的内容是:" + str); } } 【运行结果】: 从文件中读取的内容是:这些文件中的内容哦!

数据操作流DataOutputStream、DataInputStream类
import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class DataOutputStreamDemo{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.txt"); char[] ch = { 'A', 'B', 'C' }; DataOutputStream out = null; out = new DataOutputStream(new FileOutputStream(file)); for(char temp : ch){ out.writeChar(temp); } out.close(); } } A B C
现在我们在上面例子的基础上,使用DataInputStream读出内容
import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class DataOutputStreamDemo{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.txt"); DataInputStream input = new DataInputStream(new FileInputStream(file)); char[] ch = new char[10]; int count = 0; char temp; while((temp = input.readChar()) != 'C'){ ch[count++] = temp; } System.out.println(ch); } } 【运行结果】: AB
合并流 SequenceInputStream SequenceInputStream主要用来将2个流合并在一起,比如将两个txt中的内容合并为另外一个txt。下面给出一个实例:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.SequenceInputStream; /** * 将两个文本文件合并为另外一个文本文件 * */ public class SequenceInputStreamDemo{ public static void main(String[] args) throws IOException{ File file1 = new File("d:" + File.separator + "hello1.txt"); File file2 = new File("d:" + File.separator + "hello2.txt"); File file3 = new File("d:" + File.separator + "hello.txt"); InputStream input1 = new FileInputStream(file1); InputStream input2 = new FileInputStream(file2); OutputStream output = new FileOutputStream(file3); // 合并流 SequenceInputStream sis = new SequenceInputStream(input1, input2); int temp = 0; while((temp = sis.read()) != -1){ output.write(temp); } input1.close(); input2.close(); output.close(); sis.close(); } } 【运行结果】 结果会在hello.txt文件中包含hello1.txt和hello2.txt文件中的内容。
文件压缩 ZipOutputStream类 先举一个压缩单个文件的例子吧:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class ZipOutputStreamDemo1{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.txt"); File zipFile = new File("d:" + File.separator + "hello.zip"); InputStream input = new FileInputStream(file); ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream( zipFile)); zipOut.putNextEntry(new ZipEntry(file.getName())); // 设置注释 zipOut.setComment("hello"); int temp = 0; while((temp = input.read()) != -1){ zipOut.write(temp); } input.close(); zipOut.close(); } } 【运行结果】 运行结果之前,我创建了一个hello.txt的文件,原本大小56个字节,但是压缩之后产生hello.zip之后,居然变成了175个字节,有点搞不懂。 不过结果肯定是正确的,我只是提出我的一个疑问而已。 上面的这个例子测试的是压缩单个文件,下面的们来看看如何压缩多个文件。 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * 一次性压缩多个文件 * */ public class ZipOutputStreamDemo2{ public static void main(String[] args) throws IOException{ // 要被压缩的文件夹 File file = new File("d:" + File.separator + "temp"); File zipFile = new File("d:" + File.separator + "zipFile.zip"); InputStream input = null; ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream( zipFile)); zipOut.setComment("hello"); if(file.isDirectory()){ File[] files = file.listFiles(); for(int i = 0; i < files.length; ++i){ input = new FileInputStream(files[i]); zipOut.putNextEntry(new ZipEntry(file.getName() + File.separator + files[i].getName())); int temp = 0; while((temp = input.read()) != -1){ zipOut.write(temp); } input.close(); } } zipOut.close(); } } 【运行结果】 先看看要被压缩的文件吧: 接下来看看压缩之后的: 大家自然想到,既然能压缩,自然能解压缩,在谈解压缩之前,我们会用到一个ZipFile类,先给一个这个例子吧。java中的每一个压缩文件都是可以使用ZipFile来进行表示的 import java.io.File; import java.io.IOException; import java.util.zip.ZipFile; /** * ZipFile演示 * */ public class ZipFileDemo{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.zip"); ZipFile zipFile = new ZipFile(file); System.out.println("压缩文件的名称为:" + zipFile.getName()); } } 【运行结果】: 压缩文件的名称为:d:hello.zip 现在我们呢是时候来看看如何加压缩文件了,和之前一样,先让我们来解压单个压缩文件(也就是压缩文件中只有一个文件的情况),我们采用前面的例子产生的压缩文件hello.zip import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * 解压缩文件(压缩文件中只有一个文件的情况) * */ public class ZipFileDemo2{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.zip"); File outFile = new File("d:" + File.separator + "unZipFile.txt"); ZipFile zipFile = new ZipFile(file); ZipEntry entry = zipFile.getEntry("hello.txt"); InputStream input = zipFile.getInputStream(entry); OutputStream output = new FileOutputStream(outFile); int temp = 0; while((temp = input.read()) != -1){ output.write(temp); } input.close(); output.close(); } } 【运行结果】: 解压缩之前:          这个压缩文件还是175字节 解压之后产生:         又回到了56字节,表示郁闷。 现在让我们来解压一个压缩文件中包含多个文件的情况吧 ZipInputStream类 当我们需要解压缩多个文件的时候,ZipEntry就无法使用了,如果想操作更加复杂的压缩文件,我们就必须使用ZipInputStream类
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; /** * 解压缩一个压缩文件中包含多个文件的情况 * */ public class ZipFileDemo3{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "zipFile.zip"); File outFile = null; ZipFile zipFile = new ZipFile(file); ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file)); ZipEntry entry = null; InputStream input = null; OutputStream output = null; while((entry = zipInput.getNextEntry()) != null){ System.out.println("解压缩" + entry.getName() + "文件"); outFile = new File("d:" + File.separator + entry.getName()); if(!outFile.getParentFile().exists()){ outFile.getParentFile().mkdir(); } if(!outFile.exists()){ outFile.createNewFile(); } input = zipFile.getInputStream(entry); output = new FileOutputStream(outFile); int temp = 0; while((temp = input.read()) != -1){ output.write(temp); } input.close(); output.close(); } } } 【运行结果】: 被解压的文件: 解压之后再D盘下会出现一个temp文件夹,里面内容: PushBackInputStream回退流 import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PushbackInputStream; /** * 回退流操作 * */ public class PushBackInputStreamDemo{ public static void main(String[] args) throws IOException{ String str = "hello,rollenholt"; PushbackInputStream push = null; ByteArrayInputStream bat = null; bat = new ByteArrayInputStream(str.getBytes()); push = new PushbackInputStream(bat); int temp = 0; while((temp = push.read()) != -1){ if(temp == ','){ push.unread(temp); temp = push.read(); System.out.print("(回退" + (char) temp + ") "); }else{ System.out.print((char) temp); } } } } 【运行结果】: hello(回退,) rollenholt /** * 取得本地的默认编码 * */ public class CharSetDemo{ public static void main(String[] args){ System.out.println("系统默认编码为:" + System.getProperty("file.encoding")); } } 【运行结果】: 系统默认编码为:GBK 乱码的产生: import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * 乱码的产生 * */ public class CharSetDemo2{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.txt"); OutputStream out = new FileOutputStream(file); byte[] bytes = "你好".getBytes("ISO8859-1"); out.write(bytes); out.close(); } } 【运行结果】: ?? 一般情况下产生乱码,都是由于编码不一致的问题。 对象的序列化 对象序列化就是把一个对象变为二进制数据流的一种方法。 一个类要想被序列化,就行必须实现java.io.Serializable接口。虽然这个接口中没有任何方法,就如同之前的cloneable接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。 先让我们实现一个具有序列化能力的类吧: import java.io.*; /** * 实现具有序列化能力的类 * */ public class SerializableDemo implements Serializable{ public SerializableDemo(){ } public SerializableDemo(String name, int age){ this.name=name; this.age=age; } @Override public String toString(){ return "姓名:"+name+" 年龄:"+age; } private String name; private int age; } 这个类就具有实现序列化能力, 在继续将序列化之前,先将一下ObjectInputStream和ObjectOutputStream这两个类
先给一个ObjectOutputStream的例子吧:
import java.io.Serializable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; /** * 实现具有序列化能力的类 * */ public class Person implements Serializable{ public Person(){ } public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + name + " 年龄:" + age; } private String name; private int age; } /** * 示范ObjectOutputStream * */ public class ObjectOutputStreamDemo{ public static void main(String[] args) throws IOException{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( file)); oos.writeObject(new Person("rollen", 20)); oos.close(); } } 【运行结果】: 当我们查看产生的hello.txt的时候,看到的是乱码,呵呵。因为是二进制文件。
虽然我们不能直接查看里面的内容,但是我们可以使用ObjectInputStream类查看:
import java.io.File; import java.io.FileInputStream; import java.io.ObjectInputStream; /** * ObjectInputStream示范 * */ public class ObjectInputStreamDemo{ public static void main(String[] args) throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object obj = input.readObject(); input.close(); System.out.println(obj); } } 【运行结果】 姓名:rollen 年龄:20 到底序列化什么内容呢? 其实只有属性会被序列化。 Externalizable接口 被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。 当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。
现在我们来演示一下序列化和反序列话:
package IO; import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; /** * 序列化和反序列化的操作 * */ public class ExternalizableDemo{ public static void main(String[] args) throws Exception{ ser(); // 序列化 dser(); // 反序列话 } public static void ser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( file)); out.writeObject(new Person("rollen", 20)); out.close(); } public static void dser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object obj = input.readObject(); input.close(); System.out.println(obj); } } class Person implements Externalizable{ public Person(){ } public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + name + " 年龄:" + age; } // 复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用 @Override public void writeExternal(ObjectOutput out) throws IOException{ out.writeObject(this.name); out.writeInt(age); } // 复写这个方法,根据需要读取内容 反序列话的时候需要 @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{ this.name = (String) in.readObject(); this.age = in.readInt(); } private String name; private int age; } 【运行结果】: 姓名:rollen 年龄:20
本例中,我们将全部的属性都保留了下来, Serializable接口实现的操作其实是吧一个对象中的全部属性进行序列化,当然也可以使用我们上使用是Externalizable接口以实现部分属性的序列化,但是这样的操作比较麻烦, 当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么我们可以使用transient关键字进行说明: 下面举一个例子:
package IO; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * 序列化和反序列化的操作 * */ public class serDemo{ public static void main(String[] args) throws Exception{ ser(); // 序列化 dser(); // 反序列话 } public static void ser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( file)); out.writeObject(new Person1("rollen", 20)); out.close(); } public static void dser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object obj = input.readObject(); input.close(); System.out.println(obj); } } class Person1 implements Serializable{ public Person1(){ } public Person1(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + name + " 年龄:" + age; } // 注意这里 private transient String name; private int age; } 【运行结果】: 姓名:null 年龄:20
最后在给一个序列化一组对象的例子吧:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * 序列化一组对象 * */ public class SerDemo1{ public static void main(String[] args) throws Exception{ Student[] stu = { new Student("hello", 20), new Student("world", 30), new Student("rollen", 40) }; ser(stu); Object[] obj = dser(); for(int i = 0; i < obj.length; ++i){ Student s = (Student) obj[i]; System.out.println(s); } } // 序列化 public static void ser(Object[] obj) throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( file)); out.writeObject(obj); out.close(); } // 反序列化 public static Object[] dser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object[] obj = (Object[]) input.readObject(); input.close(); return obj; } } class Student implements Serializable{ public Student(){ } public Student(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名: " + name + " 年龄:" + age; } private String name; private int age; } 【运行结果】: 姓名: hello 年龄:20 姓名: world 年龄:30 姓名: rollen 年龄:40

 

原文地址:https://www.cnblogs.com/lkboy/p/4169973.html