文件流首先分类:
/*
* IO流的分类:
* 流向:
* 输入流 读取数据
* 输出流 写出数据
* 数据类型:
* 字节流:
* 字节输入流 读取数据 InputStream
* 字节输出流 写出数据 OutputStream
* 字符流:
* 字符输入流 读取数据 Reader
* 字符输出流 写出数据 Writer
* 能否直接操作文件:
* 普通流
* 包装流
*
* 注意:一般我们在探讨IO流的时候,如果没有明确说明按照那种分类,默认情况下是按照数据类型进行分类的
OutputStream--FileOutputStream:
* 需求:我要往一个文本文件中输入一句话:hello,io * * 分析: * A:这个操作最好是采用字符流(文本),但是呢,字符流是在字节流后面才出现,索引,今天我先讲解字节流如何操作 * B:由于我是要往文件中写一句话,所以我要采用字节输出流 * * 通过上面的分析后,我们发现要使用这个流:OutputStream * 但是通过查看API,我们发现它是一个抽象类,不能实例化 * 所以我们需要一个具体的子类 * 而我们要找的子类是什么名字的呢? * * 注意:每种基类的子类都是以父类名作为后缀名 * * 操作文件,所以确定使用FileOutputStream * 构造: * ·FileOutputStream(File file) * FileOutputStream(Stream name) * * 字节输出流操作步骤: * A:创建字节输出流对象 * B:写数据 * C:释放资源 * * 写数据的方式: * Writer(int ch) 写入的是该字节所代表的Ascill值,int的范围就是一个字节的范围吧 * Writer(byte[] b) 写的是连续的Ascill的连接体 * Writer(byte[] b,int offset,int length) 写的是数组的截取一部分的单个字节的连接体 * */ public class OutputStreamDemo01 { public void test01() throws IOException { // File file=new File("file.txt"); // FileOutputStream fos=new FileOutputStream(file); FileOutputStream fos=new FileOutputStream("file.txt"); /* * 创建字节输出流做了几件事情 * A:调用系统功得到文件,不存在则自己创建 * B:创建fos对象 * C:把fos对象指向这个文件 */ //写数据 //fos.write("hello,io".getBytes()); fos.write(12); //释放资源 //关闭此文件输出流并释放与此流有关的所有系统资源 fos.close(); /* * 为什么一定要close()呢? * A:让流对象变成垃圾,这样就可以被垃圾回收机制回收了 * B:通知系统去释放跟该文件相关的资源 */ //java.io.IOException:Stream Closed // fos.write("java".getBytes()); } /* * 如何实现数据的换行? * 为什么现在没有换行呢?因为你只写了字节数据,没有写入换行符号 * 如何实现呢?写入换行符号即可 * 刚才我们发现在myeclipes里面查看是换行了的,但是在windows里面的记事本打开却不行,为什么呢? * windows: * linux: * Mac: * 一些常见的高级记事本,内部是有程序识别各种换行符号的 * * 如何实现数据的追加写入? * 在构造FileOutputStream对象的时候在后面写第二个参数是否追加为true即可 * FileOutputStream(File file, boolean append) * 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 * FileOutputStream(String name, boolean append) * 创建一个向具有指定 name 的文件中写入数据的输出文件流。 * */ public void test02() throws IOException{ // OutputStream fos = new FileOutputStream("fos.txt"); OutputStream fos=new FileOutputStream("fos.txt",true); for (int x = 0; x < 10; x++) { fos.write(("hello" + x).getBytes()); // fos.write((" ").getBytes()); fos.write(" ".getBytes()); } fos.close(); } /* * 标准的加入异常处理的字节输出流 */ public void method3() { FileOutputStream fos=null; try { fos=new FileOutputStream("fos.txt"); fos.write("java".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ //如果fos不是null才需要close if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
InputStream--FileInputStream:
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 字节输入流操作步骤: * A:创建字节流输入对象 * B:调用read()方法读取数据,并把数据显示在控制台 * C:释放资源 * * 读取数据的方式: * A:int read():一次读取一个字节 * B:int read(byte[] b) 一次读写一个字节数组 */ public class InputStreamDemo01 { public void method1(){ // FileOutputStream fos=null; FileInputStream fis=null; try { // fos=new FileOutputStream("fis.txt"); // fos.write("abc".getBytes()); fis=new FileInputStream("fis.txt"); //使用read()读取 // int by=fis.read(); // System.out.println((char)by); // //第二次读取 // by=fis.read(); // System.out.println((char)by); // //第三次读取 // by=fis.read(); // System.out.println((char)by); // //我们发现代码重复度数很高,所以我们要用循环改进 // //使用循环,麻烦的是循环条件 // // by=fis.read(); // System.out.println(by); // by=fis.read(); // System.out.println(by); // //如果返回的是-1,说明到达文件末尾 int by=0; while((by=fis.read())!=-1){ System.out.print((char)by);//取读中文会出问题,因为每一次读取一个字节而一个中文两个字节,所以中文被拆分后无法成功读取出现乱码 } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ // if(fos!=null){ // try { // fos.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } } } /* * 一次读取一个字节数组: int read(byte[] b) * 读取前面的那个avi,结果用了173毫秒秒 * 尼玛,这效率的对比 */ /* * 可以看到read(byte[] b)返回的是成功读取的字节数 * * 解析: * fix的文件拆成字符是这样的: * hello world java * 第一次 数组中 hello * 第二次: wor * 第三次: ld j * 第四次: ava j * 第五次: ava j */ public void method02(){ FileInputStream fis=null; FileOutputStream fos=null; try { fos=new FileOutputStream("IO.avi"); // fis=new FileInputStream("fix.txt"); fis=new FileInputStream("C:\Users\Administrator.PMIMP83HWNIKWOV\Desktop\【批量下载】20.29_day20总结等\传智播客视频\Java视频\JAVA基础篇\day20\avi\20.01_IO流(递归概述和注意事项).avi"); // byte[] bye=new byte[5]; // int len=fis.read(bye); // System.out.println(len); // System.out.println(new String(bye)); // // len=fis.read(bye); // System.out.println(len); // System.out.println(new String(bye)); // // len=fis.read(bye); // System.out.println(len); // System.out.println(new String(bye)); // // len=fis.read(bye); // System.out.println(len); // System.out.println(new String(bye)); // // len=fis.read(bye); // System.out.println(len); // System.out.println(new String(bye)); byte[] bye=new byte[1024];//byte数组一般长度是1024或者1024的整数倍 int len=0; long startTime=System.currentTimeMillis(); while((len=fis.read(bye))!=-1){ // System.out.print(new String(bye,0,len)); fos.write(bye,0,len); } long endTime=System.currentTimeMillis(); System.out.println("一共用了"+(endTime-startTime)+"毫秒"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
复制数据的demo:
package com.IO; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; public class InputStreamAndOutputStreamDemo { /* * * 复制文本文件 * * 数据源:从哪里来 * a.txt ---读取数据 --- FileInputStream * * 目的地:到哪里去 * b.txt ---写数据 ---FileOutputStream * * 这一次写数据不会出现中文乱码这是为什么呢? * 因为我们之前读取数据是一个字节读取后就直接转化为字符输出,所以中文拆分了才乱码的 * 而现在是将一个字节写入输出流,再通过输出流写入的文件。输出流写入文件如果是中文后面会自动化做出转换 */ public static void main(String[] args) { FileOutputStream fos=null; FileInputStream fis=null; try { File file=new File("a.txt"); if(!file.exists()){ file.createNewFile(); } fos=new FileOutputStream("b.txt"); fis=new FileInputStream("a.txt"); int x=0; while((x=fis.read())!=-1){ fos.write(x); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test01(){//写点数据 FileOutputStream fos=null; try { fos=new FileOutputStream("a.txt"); fos.write("我是一个好人 对吧! guodaxia!".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /* * 计算机是如何识别什么时候该把两个字节转换为一个中文的呢? * 在计算机中中文的存储分成两个字节: * 第一个字节一定是负数 * 第二个字节常见是负数,可能是正数,但是没影响。 * * 当输出流写入字节发现是负数,它会等待与下一个字节拼成一个中文 */ public void test02(){ // String s="abcde"; // //[97, 98, 99, 100, 101] String s="我爱你,中国!"; //[-50, -46, -80, -82, -60, -29, -93, -84, -42, -48, -71, -6, -93, -95] byte[] b=s.getBytes(); System.out.println(Arrays.toString(b)); } }
字节缓冲流:BufferedInputStream和BufferedOutputStream
package com.IO; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class BufferedInputStreamAndBufferedOutputStream { /* * 我们发现使用数组一次读取多个数据可以提高效率很多。 * java在设计的时候,当然也考虑到这个问题了,所以它专门提供了带缓冲区的字节类 * 这种类被称为:缓冲区类(高效类),缓冲流是基本流的子类 * 写数据:BufferedOutputStream * 读数据:BufferedInputStream * * 构造方法可以指定缓冲区大小,但是一般我们用不上,因为默认大小一般足够了 * * 为什么不传递一个具体的文件或者文件路径作为缓冲流对象的参数呢?而是传递一个输入输出流对象? * 原因很简单,字节缓冲流仅仅提供缓冲区,是为了高效而设计的,本身的数据的来源是由基本的流对象实现的 * 举个例子:基本流对象是水,缓冲流提供的仅仅是水杯 */ public void test01() throws IOException{ // FileOutputStream fos=new FileOutputStream("bos.txt"); // BufferedOutputStream bos=new BufferedOutputStream(fos); //简单写法 BufferedOutputStream bos=new BufferedOutputStream( new FileOutputStream("bos.txt")); bos.write("hello".getBytes()); bos.close(); // fos.close(); } //花了54毫秒,所以说缓冲流对效率进行了提高 public static void test02() throws IOException { BufferedInputStream bis=new BufferedInputStream( new FileInputStream("C:\Users\Administrator.PMIMP83HWNIKWOV\Desktop\【批量下载】20.29_day20总结等\传智播客视频\Java视频\JAVA基础篇\day20\avi\20.01_IO流(递归概述和注意事项).avi")); BufferedOutputStream bos=new BufferedOutputStream( new FileOutputStream("IO.avi")); byte[] b=new byte[1024]; int len=0; long startTime=System.currentTimeMillis(); while((len=bis.read(b))!=-1){ bos.write(b, 0, len); } long endTime=System.currentTimeMillis(); System.out.println("一共花费时间:"+(endTime-startTime)+"毫秒"); bis.close(); bos.close(); } }
Reader与Writer和字节输入输出流基本一致
字符缓冲流:BufferedWriter与BufferedReader
package com.IO; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /* * BufferedReader的新方法:readLine();读取一行数据,返回String,不包含换行符 * BufferedWriter的新方法:newLine(); 根据系统来决定换行符号,写入换行符 */ public class BufferedReaderAndBufferedWriterDemo { public static void main(String[] args) throws IOException { BufferedReader fr=new BufferedReader(new FileReader("haha.txt")); String s=null; while((s=fr.readLine()) != null){ System.out.println(s); } BufferedWriter bw=new BufferedWriter(new FileWriter("xixi.txt")); bw.write("嘻嘻嘻"); bw.newLine(); bw.write("今天春游去小溪"); bw.newLine(); bw.write("抓鱼抓鱼"); bw.newLine(); bw.write("烤着吃 笑眯眯"); bw.flush(); fr.close(); bw.close(); } }
转换流:InputStreamReader与OutputStreamWriter
package com.IO; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class InputStreamReaderAndOutputStreamWriterDemo { public static void main(String[] args) { } /* * InputStreamReader(InputStream is):用默认的编码读取数据 * InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据 */ public static void test01() throws IOException { // InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt")); InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"),"utf-8"); int ch=0; while((ch=isr.read())!=-1){ System.out.print((char)ch); } } /* * OutputStreamWriter的方法: * public void write(int c); * public void write(char[] ch); * public void write(char[] ch,int offset,int len) * public void write(byte[] buff) * public void write(byte[] buff,int offset,int len) */ /* * 两个地方会刷新缓冲区。 * 1、flush方法 * 2、close方法 刷新缓冲区并关闭流 * */ public static void test02() throws IOException { OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("osw1.txt")); //写数据: // osw.write('a'); // osw.write(97); //为什么数据没有过去呢? //因为 字符=2字节,文件存储的基本单位是字节,所以需要外力 char[] chs={'a','b'}; osw.write(chs); osw.write(chs); // osw.flush();//刷新缓冲,提交给文件 osw.flush(); } }
操作基本数据类型流:DataInputStream、DataOutputStream
package com.IO; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 操作基本数据类型流 */ /* * 最好不要用数据输出流的writeBytes写入字符串,因为难以判断字符串的起始和终止,可以使用writeUTF写入 * DataOutputStream数据输出流 * 允许程序以适当方式将java基本数据类型写入输出流中。然后应用程序可以以数据输入流将数据读入 * 一些方法: * writeBoolean(Boolean v) * writeBytes(String s) * writeByte(int v) * ...... * writeUTF(String str) 以utf-8编码将字符串写入基础输出流 * DataInputStream * 一些方法: * readBoolean() * readByte() * ... * * String readLine() 已过时。 该方法无法将字节正确转换为字符。从 JDK 1.1 开始,读取文本行的首选方法是使用 BufferedReader.readLine() 方法。使用 DataInputStream 类读取文本行的程序可以改为使用 BufferedReader 类,只要将以下形式的代码: DataInputStream d = new DataInputStream(in); 替换为: BufferedReader d = new BufferedReader(new InputStreamReader(in)); * readUTF() * */ public class DataOutputStreamAndDataInputStream { public static void main(String[] args) { DataInputStream dis=null; DataOutputStream dos=null; try { dos=new DataOutputStream(new FileOutputStream("a.txt")); dis=new DataInputStream(new FileInputStream("a.txt")); // dos.writeBytes("你好"); // dos.writeChar(' '); // dos.writeChar(' '); dos.writeUTF("我是一个好人"); dos.writeChar(' '); dos.writeChar(' '); dos.writeInt(110); dos.writeBoolean(true); // dos.writeChar(' '); dos.writeDouble(12.78); //dos.writeBytes("我要报警了"); System.out.println(dis.readUTF()); System.out.println(dis.readChar()); System.out.println(dis.readChar()); System.out.println(dis.readInt()); System.out.println(dis.readBoolean()); // System.out.println(dis.readChar()); System.out.println(dis.readDouble()); //System.out.print(dis.readLine()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(dis!=null){ try { dis.close(); } catch (IOException e) { e.printStackTrace(); } } if(dos!=null){ try { dos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
序列化对象和反序列化对象流:ObjectInputStream、ObjectOutputStream
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /* * 对象的序列化和反序列化流 * 就是将对象序列化存入文件或者内存中,然后通过特定方式反序列化读取出来的两个流 * 基本要求: * 被序列化或者反序列化对象必须实现Serializable接口,拥有序列化标记 * 没有任何方法只起到标记作用的接口被称为标记接口 * 两个构造方法接受的是输入流和输出流对象 * * 序列化时候的黄色警告线问题: * 我们将一个自定义对象实现Serializable接口实现序列化操作。会报一个黄色警告线。 * 这是因为我们序列化操作的时候操作一个对象会有一个类的id,一个序列化结果的id,反序列化操作需要id吻合。我们可以点击黄色警告线,生成 * 固定id.否则如果后面更改了对象类,就会生成一个其他的id,当id不匹配的话,反序列化就会出错java.io.InvalidClassException: com.IO.Student1; local class incompatible: stream classdesc serialVersionUID = -7789306048714646111, local class serialVersionUID = 8027918234634246847 */ public class ObjectInputStreamAndObjectOutputStreamDemo { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{ // writer(); read(); } public static void writer() throws FileNotFoundException, IOException{ ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("oos.txt")); Student1 s=new Student1("林青霞",27); oos.writeObject(s); oos.close(); } public static void read() throws FileNotFoundException, IOException, ClassNotFoundException{ ObjectInputStream ois=new ObjectInputStream(new FileInputStream("oos.txt")); Object o=ois.readObject(); ois.close(); System.out.println(o); } } class Student1 implements Serializable{ /** * */ private static final long serialVersionUID = -9112575833554985447L; private String name; private int age; @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student1(String name, int age) { super(); this.name = name; this.age = age; } public Student1 (){ super(); } }
打印流:PrintStream、PrintWriter
package com.IO; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintWriter; /* * 打印流 * 此类中只有对文件的写操作,无读的操作 * 不会抛出IO异常,尽管其构造方法可能抛出异常。客户端可能会调用checkError检查是否出现错误 * 打印流也是高效的,内部使用了缓冲流作为中转 * public PrintWriter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException { this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)), false); } * PrintStream 字节打印流 * PrintWriter 字符打印流 * 首先,它是Writer的子类,可以使用Writer的一般方法 * 字段: * Protected Writer out 此PrintWriter的底层字符输出流 * 构造: * PrintWriter(File file) * PrintWriter(File file,String csn) csn:受支持的字符集名称 * printWriter(OutputStream out,boolean autoflush) * printWriter(Writer out,boolean autoFlush) * ... * 其他方法: * append(..)....追加一些信息到此流中 * boolean checkError(..)刷新且检查其错误状态 * clearError(..) 清楚错误状态 * print(..)打印 * println(..)打印并换行和支持自动刷新 * write(..)写入 * * */ public class PrintStreamAndPrintWriter { public static void main(String[] args) { PrintWriter pw=null; OutputStream out=null; try { // pw=new PrintWriter("pwMessage.txt"); //自动刷新,必须参数是其他输出流 out=new FileOutputStream("pwMessage.txt",true);//设置了自动追加 pw=new PrintWriter(out,true);//自动刷新,再遇到println、printf、format pw.write("你是谁?"); pw.print("哈哈"); pw.print(101); pw.print(true); pw.append("真无语"); pw.println("我回来了"); // pw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
内存操作流:ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter、StringReader、StringWriter
package com.IO; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.CharArrayReader; import java.io.CharArrayWriter; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; /* * 内存操作流 * 什么是内存操作流呢?就是进行的一系列读写都是在内存中进行的,只是临时存储,当程序关闭就会自动释放 * * ByteArrayInputStream * ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。 * 关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 * 构造: * ByteArrayInputStream(byte[] buf) * ByteArrayInputStream(byte[] buf, int offset, int length) * 方法: * int available() 返回可从此输入流读取(或跳过)的剩余字节数。 * *ByteArrayOutputStream * 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。 * 关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 * 构造: * ByteArrayOutputStream() * ByteArrayOutputStream(int size) * 方法: * void reset() 将此 byte 数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。 * byte[] toByteArray() 创建一个新分配的 byte 数组。 * toString() * toString(Charset charsetName) * void writeTo(OutputStream out) 将此流中的字节信息全部写入其他输出流中 * *CharArrayReader 此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 *CharArrayWriter 此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 *操作字符数组和操作字节数字差不多,我就直接演示一下例子吧 * *StringReader 此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 * void close() * void mark(int readAheadLimit) * boolean markSupported() * int read() * int read(char[] cbuf, int off, int len) * boolean ready() * void reset() 将该流重置为最新的标记,如果从未标记过,则将其重置到该字符串的开头。 * long skip(long ns) * *StringWriter 此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 * StringBuffer getBuffer() 返回该字符串缓冲区本身 * String toString() 以字符串的形式返回该缓冲区的当前值。 * write(int c) ... * append().... */ public class ByteArrayInputStreamAndByteArrayOutputStreamDemo { public static void main(String[] args) { //test01(); // test02(); test03(); } public static void test01(){ ByteArrayOutputStream bos=new ByteArrayOutputStream(); ByteArrayInputStream bis=null; try { bos.write("what should I do!郭大侠".getBytes()); System.out.println(bos.toString()); System.out.println(bos.toString("ISO-8859-1")); bis=new ByteArrayInputStream(bos.toByteArray()); bos.writeTo(System.out); System.out.println(); int len=0; byte[] b=new byte[1024]; while((len=bis.read(b))!=-1){ System.out.print(new String(b,0,len)); } } catch (IOException e) { e.printStackTrace(); } } public static void test02(){ CharArrayWriter caw=null; CharArrayReader car=null; caw=new CharArrayWriter(); caw.append("nice to meet you 郭大侠"); caw.append('a'); car=new CharArrayReader(caw.toCharArray()); int c=0; try { while((c=car.read())!=-1){ System.out.print((char)c); } } catch (IOException e) { e.printStackTrace(); } } public static void test03(){ StringWriter s=new StringWriter(); s.append('h'); s.append("你好"); s.write("nice to meet you !"); System.out.println(s.toString()); System.out.println(s.getBuffer()); StringReader sr=new StringReader(s.toString()); int i=0; try { while((i=sr.read())!=-1){ System.out.print((char)i); } } catch (IOException e) { e.printStackTrace(); } } }
合并流:SequenceInputStream
package com.IO; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.util.Vector; /* * 合并流 * 将两个或者多个InputStream合并成为一个InputStream * 主要是两个构造,其他方法一样: * * SequenceInputStream(Enumeration<? extends InputStream> e) * 通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。 * SequenceInputStream(InputStream s1, InputStream s2) * 通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。 * * */ public class SequenceInputStreamDemo { public static void main(String[] args) { // test01(); try { test02(); } catch (IOException e) { e.printStackTrace(); } } public static void test01(){ //将test01.java test02.java都放到t.txt中去 //原来的做法是使用两个输入流,分别写入输出流中。现在使用SequenceInputStream SequenceInputStream sis=null; BufferedOutputStream bw=null; BufferedInputStream bis=null; try { sis=new SequenceInputStream(new FileInputStream("Test01.java"),new FileInputStream("Test02.java")); bw=new BufferedOutputStream(new FileOutputStream("t.txt")); bis=new BufferedInputStream(sis); byte[] b=new byte[1024]; int len=0; while((len=bis.read(b))!=-1){ bw.write(b, 0, len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(sis!=null){ try { sis.close(); } catch (IOException e) { e.printStackTrace(); } } if(bw!=null){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } if(bis!=null){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void test02() throws IOException{ //复制多个文件到一个txt Vector<InputStream> v=new Vector<InputStream>(); v.add(new FileInputStream("Test01.java")); v.add(new FileInputStream("Test02.java")); v.add(new FileInputStream("Study01.java")); SequenceInputStream sis=new SequenceInputStream(v.elements()); BufferedInputStream bis=new BufferedInputStream(sis); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("t1.txt")); byte[] b=new byte[1024]; int len=0; while((len=bis.read(b))!=-1){ bos.write(b, 0, len); } if(sis!=null){ sis.close(); } if(bis!=null){ bis.close(); } if(bos!=null){ bos.close(); } } }
标准输入输出流:System.in、System.out
package com.IO; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintStream; /* * System类中 * static InputStream in; //标准输入流 * static OutputStream out //标准输出流 是一个IO操作写入信息到控制台的打印流 */ public class System_inAndSystem_outDemo { public static void main(String[] args) { // test01(); try { // test02(); test03(); } catch (IOException e) { e.printStackTrace(); } } public static void test01(){ PrintStream ps=System.out; ps.println("你好啊"); } public static void test03() throws IOException{ PrintStream ps=System.out; BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(ps)); bw.write("你好啊"); bw.newLine(); bw.flush(); } public static void test02() throws IOException{ //第三种键盘输入获取的 InputStream is=System.in; //最好一次取读一行,所以想要使用readLine,但只能接受Reader BufferedReader br=new BufferedReader(new InputStreamReader(is)); System.out.println("请输入一个文字:"); String s=br.readLine(); System.out.println("输入的是:"+s); System.out.println("请输入一个数字:"); s=br.readLine(); int number=Integer.parseInt(s); System.out.println("您输入的数字是:"+number); } }
随机访问流:RandomAccessFile
package com.IO; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; /* * 随机访问流 * java.io下的,但是父类是Object,支持读写操作。 * 构造: * RandomAccessFile(File file, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 * RandomAccessFile(String name, String mode) * mode以及其含义: * "r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 * "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 * "rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 * "rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 * 其他特殊方法: * getFilePointer 获取指针偏移量 * public void seek(long pos) 设置偏移量 * public int skipBytes(int n) 跳过一定字节 */ public class RandomAccessFileDemo { public static void main(String[] args) { try { RandomAccessFile ra=new RandomAccessFile("randomAccess.txt","rw"); ra.writeBytes("hello"); //指针因为写完就到了最下面,所以需要重新定向 ra.seek(0); String s=ra.readLine(); System.out.println(s); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
一些IOtest:
package com.IO; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; /* * 复制文本文件 */ public class Test01 { public static void main(String[] args) { } public void test01() { // 文本文件使用的是字符流 // 最快效率就使用字符缓冲流,数组形式 BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new FileReader("a.txt")); bw = new BufferedWriter(new FileWriter("b.txt")); char[] ch = new char[1024]; int len = 0; long startTime = System.currentTimeMillis(); while ((len = br.read(ch)) != -1) { bw.write(ch, 0, len); bw.flush(); } long endTime = System.currentTimeMillis(); System.out.println("一共花费时间:" + (endTime - startTime) + "毫秒"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (bw != null) { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test02() { // 图片只能使用字节流 // 效率最快的是字节缓冲流,数组 BufferedOutputStream bos = null; BufferedInputStream bis = null; try { bos = new BufferedOutputStream(new FileOutputStream("b.png")); bis = new BufferedInputStream(new FileInputStream("a.png")); byte[] b = new byte[1024]; int len = 0; while ((len = bis.read(b)) != -1) { bos.write(b, 0, len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test03(){ //把ArrayList集合中的字符串数据存储到文本文件 //字符串的话使用字符流 ArrayList<String> stringArray=new ArrayList<String>(); stringArray.add("nice to meet you!"); stringArray.add("I am guoZhen"); stringArray.add("My job is java , I think I can do it well"); BufferedWriter bw=null; try { bw=new BufferedWriter(new FileWriter("stringArray.txt")); for(String s:stringArray){ bw.write(s); bw.newLine();//集合中的每一个元素都换行比较好 } } catch (IOException e) { e.printStackTrace(); }finally{ if(bw!=null){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test04(){ //从文本文件中读取数据(每一行为一个字符串数据)到集合中,并遍历集合 BufferedReader br=null; ArrayList<String> al=new ArrayList<String>(); try { File f=new File("stringArray.txt"); if(!f.exists()){ f.createNewFile(); } br=new BufferedReader(new FileReader(f)); String s=null; while((s=br.readLine())!=null){ al.add(s); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } for(String s:al){ System.out.println(s); } } } package com.IO; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Test02 { public static void main(String[] args) { //复制单极文件夹 //文件夹里面的文件不可预见,所以使用字节流 //复制文件夹主要是先创建一个文件夹,再将文件写入文件夹中去 //file.getName()得到的是单纯的name+后缀 //输出流使用中会自动创建文件但是如果文件有父文件夹且不存在的时候会报错 Test02 t=new Test02(); // t.copyFile("Games\俄罗斯方块", "copy_1"); t.copyDir("Games", "copy_2"); } /* * 要求:复制单极文件夹 将源文件夹拷贝到目标文件夹下 * 参数: * 源文件夹 * 目标文件夹 */ public void copyFile(String src,String dest){//f1源文件夹 f2存储位置 File f1=new File(src); File f2=new File(dest); if(!f2.exists()){ f2.mkdirs(); } File dir=new File(f2.getPath()+"\"+f1.getName()); if(!dir.exists()){ dir.mkdirs(); } File[] files=f1.listFiles(); for(File f:files){ if(f.isFile()){ File dest1=new File(dir.getPath()+"\"+f.getName()); File src1=f; copy(dest1,src1); } } } /* * 复制常见文件夹,或者文件 * 分析: * 判断 * 文件: * 直接复制到指定路径下 * 文件夹: * 就在指定路径下创建一个同名文件夹 * 取得该文件夹下的所有文件的数组 * 遍历数组,将数组每一个元素作为参数,递归。当然,目标路径也要进行一点变化传递 */ public void copyDir(String src,String dest){//f1源文件夹 f2存储位置 File f1=new File(src); File f2=new File(dest); if(!f2.exists()){ f2.mkdirs(); } File dir=new File(f2.getPath()+"\"+f1.getName()); if(f1.isFile()){ copy(dir,f1); }else{ if(!dir.exists()){ dir.mkdirs(); } File[] files=f1.listFiles(); for(File f:files){ copyDir(f.getPath(),dir.getPath()); } } } public void copy(File dest,File src){//将一个文件复制内容到另一个文件 BufferedInputStream bis=null; BufferedOutputStream bos=null; try { bis=new BufferedInputStream(new FileInputStream(src)); bos=new BufferedOutputStream(new FileOutputStream(dest)); int len=0; byte[] b=new byte[1024]; while((len=bis.read(b))!=-1){ bos.write(b, 0, len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(bis!=null){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if(bos!=null){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } package com.IO; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Scanner; public class Test03 { public static void main(String[] args) { Test03 t=new Test03(); //t.test01(); // t.test02(); ReaderDemo rd=null; try { rd=new ReaderDemo(new FileReader("b.txt")); String s=null; ReaderDemo.setRowNumber(10); while((s=rd.readLine())!=null){ System.out.print(rd.getRowNumber()+": "); System.out.println(s); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(rd!=null){ try { rd.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test03(){ //用Reader模拟BufferedReader的readLine()功能 } public void test02(){ /* * 已知s.txt文件中有这样的一个字符串:“hcexfgijkamdnoqrzstuvwybpl”请编写程序读取数据内容,把数据排序后写入ss.txt中。 * 分析: * 字符串先拆分成char数组,char数组实现自然排序 * 再写入文件 * 使用字符流 */ String str="hcexfgijkamdnoqrzstuvwybpl"; char[] chs=str.toCharArray(); Arrays.sort(chs); BufferedWriter bis=null; try { bis=new BufferedWriter(new FileWriter("stringMessage.txt")); bis.write(chs); // bis.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(bis!=null){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void test04(){ //自定义类模拟LineNumberReader的特有功能,获取每次读取数据的行号 } public void test01(){ /* 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件 * 分析: * 1、创建学生类 * 2、创建ArrayList集合 * 3、键盘录入学生信息并存入ArrayList * 4、Collections.sort()并构建自定义排序器排序 * 5、遍历集合并且写入文本文件 * 6、文件操作可以使用BufferedWriter */ ArrayList<Student> al=new ArrayList<Student>(); for(int i=1;i<=5;i++){ Scanner sc=new Scanner(System.in); Student s=new Student(); System.out.print("请输入第"+i+"名学生姓名:"); s.setName(sc.nextLine()); System.out.print("请输入第"+i+"名学生语文成绩:"); s.setChinese(sc.nextInt()); System.out.print("请输入第"+i+"名学生数学成绩:"); s.setMath(sc.nextInt()); System.out.print("请输入第"+i+"名学生英语成绩:"); s.setEnglish(sc.nextInt()); al.add(s); } Collections.sort(al, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getCountScore()-o1.getCountScore(); } }); BufferedWriter bw=null; try { bw=new BufferedWriter(new FileWriter("studengMessage.txt")); for(Student s:al){ bw.write(s.toString()); bw.newLine(); } } catch (IOException e) { e.printStackTrace(); }finally{ if(bw!=null){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Student{ private String name; private int chinese; private int math; private int english; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getChinese() { return chinese; } public void setChinese(int chinese) { this.chinese = chinese; } public int getMath() { return math; } public void setMath(int math) { this.math = math; } public int getEnglish() { return english; } public void setEnglish(int english) { this.english = english; } public Student(String name, int chinese, int math, int english) { super(); this.name = name; this.chinese = chinese; this.math = math; this.english = english; } public Student() { super(); } public int getCountScore(){ return chinese+math+english; } @Override public String toString() { return "Student [name=" + name + ", chinese=" + chinese + ", math=" + math + ", english=" + english + "]"; } } class ReaderDemo{ java.io.Reader Reader; private static int rowNumber=0; public ReaderDemo(java.io.Reader r){ Reader=r; } public static void setRowNumber(int rowNumber) { ReaderDemo.rowNumber = rowNumber-1; } public int getRowNumber(){ return rowNumber; } public String readLine() throws IOException{ // byte[] b=System.getProperty("line.separator").getBytes();//获取当前系统换行符号 //我想多了。。。。。。 int len=0; StringBuilder sb=new StringBuilder(); while((len=Reader.read())!=-1){ // if(len==){ // // } // if(len==b[b.length-1]){ // break; // } if(len==' '){ continue; }else if(len==' '){ rowNumber++; return sb.toString(); } sb.append((char)len); } return null; } public void close() throws IOException{ Reader.close(); } } package com.IO; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Test04 { public static void main(String[] args) { //使用PrintWriter改进复制文本 /* * 源:Study01.java Reader BufferedReader * 目标:copy.java Writer BufferedWriter PrintWriter */ BufferedReader br=null; PrintWriter pw=null; try { br=new BufferedReader(new FileReader("Study01.java")); pw=new PrintWriter(new FileWriter("copy.java"),true); String s=null; while((s=br.readLine())!=null){ pw.println(s); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(br!=null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } } package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import java.util.Scanner; import java.util.Set; public class Test05 { public static void main(String[] args) throws FileNotFoundException, IOException { Test05 t=new Test05(); // t.test01(); t.test02(); } public void test01() throws FileNotFoundException, IOException{ /* *需求:有一个程序user.txt,数据是键值对形式,但不知道内容,写一个程序判断是否有:list这样的键存在,如果有,其值改变为100 */ Properties prop=new Properties(); prop.load(new FileInputStream("user.txt")); Set<String> set=prop.stringPropertyNames(); boolean flag=false; for(String s:set){ if(s.equals("list")){ prop.setProperty(s, "100"); flag=true; break; } } if(flag){ System.out.println("改写成功!"); }else{ System.out.println("没有找到该键"); } } public void test02() throws IOException{ //猜数字小游戏:只能用5次,超过五次提示:游戏试玩已经结束,请付费 //让它每走一次就在文件中记录一下。然后取读文件作为判断。为什么存储在文件而不是内存呢?因为内存会随着程序的重启而刷新 //我这里使用RandomAccessFile是因为它既可读又可写 // RandomAccessFile ra=new RandomAccessFile(new File("count.txt"), "rw"); // ra.writeInt(5); // int len=0; /* * java.io.EOFException at java.io.RandomAccessFile.readInt(RandomAccessFile.java:725)发生这个错误,是因为这里读取Int是使用的4个字节读取的 */ // System.out.println(ra.readInt()); // if((len=ra.readInt())>0){ // ra.seek(0); // ra.writeInt(len-1); // GuessNumber.start(); // // }else{ // System.out.println("游戏试玩已经结束,请付费后再使用!"); // } //----------我使用Properties试一次 Properties p=new Properties(); p.load(new FileInputStream("count1.txt")); int c=Integer.parseInt(p.getProperty("count")); if(c>0){ p.setProperty("count", String.valueOf(c-1)); p.store(new FileOutputStream("count1.txt"), null); GuessNumber.start(); }else{ System.out.println("游戏试玩已经结束,请付费后再使用!"); } } } class GuessNumber { private GuessNumber(){ } public static void start(){ int number=(int)(Math.random()*100)+1; Scanner sc=new Scanner(System.in); int count=0; while(true){ count++; System.out.println("请输入数据(1~100):"); int guessNumber=sc.nextInt(); if(guessNumber>number){ System.out.println("你猜的数据"+guessNumber+"大了"); }else if(guessNumber<number){ System.out.println("你猜的数据"+guessNumber+"小了"); }else{ System.out.println("恭喜你,"+count+"次就猜中了!"); break; } } } }