Java学习之IO流

来源:互联网 发布:电脑usb端口控制管理 编辑:程序博客网 时间:2024/04/30 23:14
什么是IO:
IO即数据的输入输出。将外设的数据读到内存中就是输入,将内存中数据写入到外设中就是输出。
IO流常见的基类:
字节流的抽象基类:
InputStream, OutputStream
字符流的抽象基类:
Reader, Writer
这四个类的子类都是以父类名称作为子类名称的后缀,如InputStream的子类FileInputStream, Writer的子类:FileWriter.
如果操作文字数据,优先考虑字符流。
例:拷贝文件

public class CopyTest {
    public static void main(String[] args) {
        FileReader fileReader = null;
        FileWriter fileWriter = null;
        try {
            fileReader = new FileReader("from.txt");
            fileWriter = new FileWriter("to.txt");
            char[] arr = new char[5];//临时容器,用于缓存读到的字符
            int len = 0;
            while ((len=fileReader.read(arr))!=-1) {
                fileWriter.write(arr,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if (fileWriter!=null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileReader!=null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
BufferedReader还有一个有用的子类:LineNumberReader
此类可以跟踪行号,定义了setLineNumber()和getLineNumber()方法
例:读取一个文件,并在每行前加上行号
public class LineNumberReaderDemo {
    public static void main(String[] args) throws IOException{ //简化demo代码,暂不处理异常  
        FileReader fr = new FileReader("demo.txt");
        LineNumberReader lnr = new LineNumberReader(fr);
        String line = null;
        while ((line = lnr.readLine())!=null) {
            System.out.println(lnr.getLineNumber()+":"+line);
        }
        lnr.close();
    }
}  

字符流的缓冲区
缓冲区的出现提高了读写效率
对应的类:
BufferedWriter,BufferedReader.
缓冲区要结合流才可以使用,对流的功能进行了增强。可以把缓冲区想像成超市的小推车,必须要有货物在里面才起作用。缓冲区不调用资源,仅仅起到提高效率的作用。缓冲区的关闭就是关闭的流对象
仍然是拷贝文件的例子:

public class BufferDemo {
    public static void main(String[] args) {
        bufferReadAndWrite(new File("from.txt"),new File("to.txt"));
    }
    public static void bufferReadAndWrite(File from, File to) {
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        FileWriter fileWriter = null;
        BufferedWriter bufferedWriter = null;
        try {
            fileReader = new FileReader(from);
            bufferedReader = new BufferedReader(fileReader);
            fileWriter = new FileWriter(to);
            bufferedWriter = new BufferedWriter(fileWriter);
            String string = null;
            while ((string = bufferedReader.readLine()) != null) {
                bufferedWriter.write(string);
                bufferedWriter.newLine();
                bufferedWriter.flush();  
            }
           
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if (bufferedReader!=null) {
                try {
                    bufferedReader.close();//同时关闭了流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedWriter!=null) {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
字节流:
基本操作和字符流相同,但它不仅可以操作字符,还可以操作其它媒体文件
例:拷贝一个.avi文件
public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("from.avi");
        FileOutputStream fos = new FileOutputStream("to.avi");
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf))!=-1) {
            fos.write(buf, 0, len);
            fos.flush();
        }
        fos.close();
        fis.close();
    }
}
仍然是上面的例子,但是使用缓冲区:
public class BufferedInputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("from.avi");
        FileOutputStream fos = new FileOutputStream("to.avi");
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int len = 0;
        while ((len = bis.read())!=-1) {
            bos.write(len);
        }
        bos.close();
        bis.close();
    }
}

转换流:InputStreamReader,OutputStreamWriter
InputStreamReader:将字节流转换成字符流
OutputStreamWriter:将字符流转换成字节流
转换流还可以按指定编码表进行编码和解码
什么时候用转换流:
1,当目标或源对应的是字节流,但操作的却是文本数据,可以使用转换流作为桥梁
2,一旦操作的文本涉及指定编码表进行编码和解码,必须使用转换流
例:将输入的字符串变成大写输出,若输入over则结束
public class SwitchStreamAndReader {
    public static void main(String[] args) throws IOException {
   
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(System.out));
        String a = null;
        while ((a=br.readLine())!=null) {
            if("over".equals(a)) break;
            bos.write(a.toUpperCase());
            bos.newLine();
            bos.flush();
        }
    }
}
流的操作规律:
想要知道开发时用到哪些对象,只要通过四个“明确”就可以了
1,明确源和目的
    源:InputStream    Reader
    目的: OutputStream   Writer
2,明确数据是否是纯文本信息
    源:是纯文本:Reader   否:InputStream
    目的:是纯文本:Writer  否:OutputStream
3,明确具体的设备
    源:硬盘:File
            键盘:System.in
            内存:数组
            网络:Socket流
    目的:硬盘:File
                控制台:System.out
                内存:数组
                网络:Socket流
4,是否需要其它功能
    a,是否需要高效(缓冲区),是,就加上buffer

综合示例
public class ReaderAndWriter {
    public static void main(String[] args) throws IOException {
       // 复制一个文本文件
        copyFile();
        //读取键盘信息,并写入到文件 
        keyToFile();
        //将一个文本文件输出到控制台
        FileToConsole();
        //读取键盘输入字符串显示到控制台
        KeyToConsole();
        //将中文字符串按UTF-8写入文件 
        chToFile();
        
    }
    private static void chToFile() throws IOException {
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file5.txt"),"UTF-8"));
        bufferedWriter.write("你好");
        bufferedWriter.close();
    }
    private static void KeyToConsole() throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
        String str = null;
        while ((str= bufferedReader.readLine())!=null) {
            bufferedWriter.write(str);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        bufferedWriter.close();
        bufferedReader.close();
    }
    private static void FileToConsole() throws IOException  {
        BufferedReader bufferedReader = new BufferedReader(new FileReader("file4.txt"));
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
        String str = null;
        while ((str= bufferedReader.readLine())!=null) {
            bufferedWriter.write(str);
            bufferedWriter.flush();
            bufferedWriter.newLine();
        }
        bufferedWriter.close();
        bufferedReader.close();
    }
    private static void keyToFile() throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("file3.txt")));
        String str = null;
        while ((str= bufferedReader.readLine())!=null) {
            bufferedWriter.write(str);
            bufferedWriter.flush();
            bufferedWriter.newLine();
        }
        bufferedWriter.close();
        bufferedReader.close();
    }
    private static void copyFile() throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(
                "file1.txt"));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
                "file2.txt"));
        String str = null;
        while ((str = bufferedReader.readLine()) != null) {
            bufferedWriter.write(str);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        bufferedWriter.close();
        bufferedReader.close();
    }
}  
打印流 PrintStream PrintWriter 
为其他流添加功能,使它们能方便打印各种数据值的表式形式 。不会抛IO异常
public class PrintDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(new FileWriter("out.txt"),true);
        String str = null;
        while ((str = br.readLine())!=null) {
            if ("over".equals(str)) {
                break;
            }
            pw.println(str);
        }
    }
}  
合并数据:SequenceInputStream
例:将几个文本文件合并到一个文件 
public class MergeFileDemo {
    public static void main(String[] args) throws IOException {
        Vector<FileInputStream> vector = new Vector<FileInputStream>();
        vector.add(new FileInputStream("file1.txt"));
        vector.add(new FileInputStream("file2.txt"));
        vector.add(new FileInputStream("file3.txt"));
        vector.add(new FileInputStream("file4.txt"));
        Enumeration<FileInputStream> e = vector.elements();
        
        SequenceInputStream sis = new SequenceInputStream(e);
        BufferedReader bReader = new BufferedReader(new InputStreamReader(sis));
        BufferedWriter bWriter = new BufferedWriter(new FileWriter("mergedFile.txt"));
        String str = null;
        while ((str=bReader.readLine())!=null) {
            bWriter.write(str);
            bWriter.newLine();
            bWriter.flush();
        }
        bWriter.close();
        bReader.close();
        
    }
}
对象的序列化与反序列化:ObjectOutputStream ObjectInputStream
被操作的对象必须实现Serializable接口,此接口用于给被序列化的类加入ID号,用于判断类和对象是否是同一版本
public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectOutputStream oStream = new ObjectOutputStream(new FileOutputStream("person.object"));
        oStream.writeObject(new Person("小张",18));
        oStream.close();
        ObjectInputStream isStream = new ObjectInputStream(new FileInputStream("person.object"));
        Person person = (Person) isStream.readObject();
        System.out.println(person.getName()+":"+person.getAge());
    }
}
class Person implements Serializable{
    private String name;
    private int age;
    public Person(String name,int age) {
        this.name = name;
        this.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;
    }
} 
管道流:PipedInputStream PipedOutputStream
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。
public class PipeDemo {
    public static void main(String[] args) throws IOException {
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();
        in.connect(out);//将管道连接起来
        new Thread(new Input(in)).start();
        new Thread(new Output(out)).start();
    }
    
}
class Input implements Runnable{
    private PipedInputStream inputStream;
    public Input(PipedInputStream inputStream) {
        this.inputStream = inputStream;
    }
    public void run() {
        try {
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);
            String str = new String(buf,0,len);
            System.out.println("s="+str);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class Output implements Runnable{
    private PipedOutputStream outputStream;
    public Output(PipedOutputStream outputStream) {
        this.outputStream = outputStream;
    }
    public void run() {
        try {
            outputStream.write("管道输出流".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
操作内存的流:ByteArrayInputStream  ByteArrayOutputStream
ByteArrayInputStream  
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
ByteArrayOutputStream 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
这两个流关闭无效,在关闭后都可再次被调用(因为不涉及底层资源)而不会产生任何IO异常。
public class ByteArrayStreamDemo {
    public static void main(String[] args) {
        ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int a = 0;
        while ((a=bis.read())!=-1) {
            bos.write(a);
        }
        System.out.println(bos.toString());
    }
} 
0 0