Java IO

Java IO

Java IO即Java 输入输出系统。不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO(文件、控制台、网络),我们还要考虑具体和它们的通信方式(顺序、随机、二进制、按字符、按字、按行等等)。Java类库的设计者通过设计大量的类来攻克这些难题,这些类就位于java.io包中。

1.流

在Java IO中,流是一个核心的概念。流从概念上来说是一个连续的数据流。你既可以从流中读取数据,也可以往流中写数据。流与数据源或者数据流向的媒介相关联。在Java IO中流既可以是字节流(以字节为单位进行读写),也可以是字符流(以字符为单位进行读写)。

2.IO分类和用途

IO流的分类

IO流的分类可以从三个维度进行描述
流向:输入流和输出流
单位:字节流和字符流
功能:节点流和处理流

IO流的用途

文件访问
网络访问
内存缓存访问
管道
JavaIO流的详细划分.jpg

3.Java IO流的基本用法

3.1 文件流

FileInputStream/FileOutputStream代码

/**
 * FileInputStream FileOutputStream 文件字节输入输出流
 * 查看源码可知
 * FileInputStream FileOutputStream 的close() 实现了管理资源方法
 * FileOutputStream 的flush()方法为空。说明FileOutputStream 没有缓冲区
 * Created by lyyz on 2018/5/24.
 */
public class FileByteEg {

    /**
     * 字节流形式读取文件内容
     * @return
     */
    public byte[] readFileWithByte(){
        byte[] result = null;
        try {
            File file = new File("D:\\filetest.txt");
            InputStream fileInputStream = new FileInputStream(file);
            result = new byte[(int)file.length()];
            fileInputStream.read(result);

            fileInputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 字节流形式写入文件
     * @param input
     */
    public void writeFIleWithByte(String input){
        try {
            byte[] bytes = input.getBytes();
            File file = new File("D:\\filetest.txt");
            OutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String input = "读写文件 用字节流的形式 FileOutputStream/FileInputStream";
        FileByteEg fileByteEg = new FileByteEg();
        fileByteEg.writeFIleWithByte(input);
        byte[] result = fileByteEg.readFileWithByte();
        System.out.println(new String(result));
    }
}

FileReader/FileWriter代码

/**
 * FileReader FileWriter 文件字符输入输出流
 * FileReader FileWriter 是通过StreamDecoder StreamEncoder 字符流字节流编码解码转换器实现的。
 * 其实本质还是操作FileInputStream FileOutputStream 只不过是通过StreamDecoder StreamEncoder 在中间处理下数据。将字节变成字符
 * 从源码可以看出
 * FileReader 继承InputStreamReader 而 InputStreamReader 继承 Reader
 * FileWriter 继承OutputStreamWriter 而 OutputStreamWriter 继承 Writer
 * FileReader FileWriter 类没有实现read(),writer()等方法 只有构造函数
 * 1,FileReader的构造函数是将传入的文件new FileInputStream() 并将文件字节流作为参数调用父类InputStreamReader的构造函数
 * 2,InputStreamReader的构造函数 将文件字节流 传递给StreamDecoder.forInputStreamReader()方法构建 字节流解码转换器
 *,3,而我们调用read()方法实际是调用的StreamDecoder.read()方法。
 * Created by lyyz on 2018/5/24.
 */
public class FileStringEg {
    /**
     * 字符流形式写入文件
     * @param input
     */
    public void writeFileWithString(String input){
    try {
        File file = new File("D://filetest.txt");
        Writer fileWriter = new FileWriter(file);
        fileWriter.write(input);
        fileWriter.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

    /**
     * 字节流形式读取文件
     * @return
     */
    public char[] readFileWithString(){
    char[] result = null;
    try {
        File file = new File("D://filetest.txt");
        Reader fileReader = new FileReader(file);
        result = new char[(int)file.length()];
        fileReader.read(result);
        fileReader.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return result;
}

    public static void main(String[] args) {
        FileStringEg fileStringEg = new FileStringEg();
        fileStringEg.writeFileWithString("读写文件 用字符流的形式 FileWriter/FileReader");
        char[] result = fileStringEg.readFileWithString();
        System.out.println(new String(result));
    }
}

3.2内存流

内存流,其实就是将数据存入到内存中,像
ByteArrayInputStream,ByteArrayOutputStream,
CharArrayReader,CharArrayWriter,StringReader,StringWriter
其实实现都是将数据以数组形式存入到内存中。
使用是注意不要将大的数据存入内存中。否则内存溢出。注意内存泄漏问题。

ByteArrayInputStream/ByteArrayOutputStream代码

/**
 * 实现类似内存虚拟文件的功能
 * ByteArrayInputStream本身操作的是一个数组,并没有打开文件描述之类的,所有不需要关闭流
 * ByteArrayInputStream 内部有一个字节数组存放写入内存中的数据(protected byte buf[];)
 * 通过ByteArrayInputStream 构造方法传入数组的大小,默认为1024
 * Created by lyyz on 2018/5/24.
 */
public class MemoryByteEg {
    /**
     * 写入数据到内存中 返回写入的ByteArrayOutputStream 等读取时候要从此对象中取数据
     * @param input
     * @return
     */
    public ByteArrayOutputStream writeMemoryWithByte(byte[] input){
        ByteArrayOutputStream result = null;
        try {
            //初始化buf[] 容量
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
            result = byteArrayOutputStream;
            byteArrayOutputStream.write(input);
            //ByteArrayOutputStream 中close()方法为空
            //不用写close()这个因为就没有调用底层资源,所以也就不用释放资源
            //byteArrayOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从内存读取数据
     * @param byteArrayOutputStream 写数据的 ByteArrayOutputStream
     * @return
     */
    public byte[] readMemoryWithByte(ByteArrayOutputStream byteArrayOutputStream ){
        byte[] result = null;
        try {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            byteArrayInputStream.read(result=new byte[byteArrayOutputStream.size()]);
            //ByteArrayInputStream 中close()方法为空
            //不用写close()这个因为就没有调用底层资源,所以也就不用释放资源
            //byteArrayInputStream.close();
            //使用完毕设置为NULL 让GC回收
            byteArrayOutputStream = null;
            byteArrayInputStream = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) {
        MemoryByteEg memoryByteEg = new MemoryByteEg();
        String input = "读写内存数据 通过ByteArrayInputStream/ByteArrayOutputStream";
        ByteArrayOutputStream byteArrayOutputStream = memoryByteEg.writeMemoryWithByte(input.getBytes());
        byte[] result = memoryByteEg.readMemoryWithByte(byteArrayOutputStream);
        System.out.println(new String(result));
    }
}

CharArrayReader/CharArrayWriter代码

/**
 * CharArrayReader 本身操作的是char buf[];数组  并没有打开文件描述之类的,所有不需要关闭流
 * 用法与ByteArrayInputStream相同
 * Created by lyyz on 2018/5/24.
 */
public class MemoryCharEg {
    /**
     * 写入数据到内存中 返回写入的CharArrayWriter 等读取时候要从此对象中取数据
     * @param input
     * @return
     */
    public CharArrayWriter writeMemoryWithChar(char[] input){
        CharArrayWriter result = null;
        //初始化     protected char buf[]; 容量
        try {
            CharArrayWriter charArrayWriter = new CharArrayWriter(1024);
            charArrayWriter.write(input);
            result = charArrayWriter;
            //CharArrayWriter 中close()方法为空
            //不用写close()这个因为就没有调用底层资源,所以也就不用释放资源
            //charArrayWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从内存读取数据
     * @param charArrayWriter  写数据的 charArrayWriter 对象
     * @return
     */
    public char[] readMemoryWithChar(CharArrayWriter charArrayWriter){
        char[] result = null;
        try {
            CharArrayReader charArrayReader = new CharArrayReader(charArrayWriter.toCharArray());
            charArrayReader.read(result = new char[charArrayWriter.size()]);
            //CharArrayReader 中close()方法为空
            //不用写close()这个因为就没有调用底层资源,所以也就不用释放资源
            //charArrayReader.close();

            //使用完毕设置为NULL 让GC回收
            charArrayReader = null;
            charArrayWriter = null;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    public static void main(String[] args) {
        MemoryCharEg memoryCharEg = new MemoryCharEg();
        String input = "读写内存数据 通过CharArrayReader/CharArrayWriter";
        CharArrayWriter charArrayWriter = memoryCharEg.writeMemoryWithChar(input.toCharArray());
        char[] result = memoryCharEg.readMemoryWithChar(charArrayWriter);
        System.out.println(new String(result));
    }
}

StringReader/StringWriter代码

/**
 * 字符串流 与CharArray 相同 存入内存,不涉及到资源,close()方法 为空实现
 *     private StringBuffer buf;
 * StringWriter 内部是基于StringBufffer实现的
 * Created by lyyz on 2018/5/24.
 */
public class MemoryStringEg {
    /**
     * 写入内存
     * @param input
     * @return
     */
    public StringWriter writerMemoryWithString(String input){
        StringWriter result = null;
        //    private StringBuffer buf; 初始化大小
        StringWriter stringWriter = new StringWriter(1024);
        stringWriter.write(input);
        result = stringWriter;
        return result;
    }

    /**
     * 从内存中读取数据
     * @param stringWriter
     * @return
     */
    public String readMemoryWithString(StringWriter stringWriter){
        String result = null;
        //内存StringWriter是通过StringBuffer实现的所以 直接从StringWriter中拿去StringBuffer就可以实现 读取数据
        //result = stringWriter.getBuffer().toString();
        // StringWriter 重写了toString()方法, 调用StringBufferd的toString()方法
        //result = stringWriter.toString();
        char[] chars = new char[stringWriter.toString().length()];
        try {
            StringReader stringReader = new StringReader(stringWriter.toString());
            stringReader.read(chars);
            result = new String(chars);
            // 使用完毕设置为NULL 让GC回收
            stringWriter = null;
            //close() 方法  实现str = null; reader 方法清除内部的str 没有内存泄漏问题
            stringReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) {
        MemoryStringEg memoryStringEg = new MemoryStringEg();
        String input = "读写内存数据 通过StringReader/StringWriter";
        StringWriter stringWriter = memoryStringEg.writerMemoryWithString(input);
        String result = memoryStringEg.readMemoryWithString(stringWriter);
        System.out.println(result);
    }
}

3.3管道流

管道流其实也是操作内存中的数组实现的。具体可查看源码。多用于线程之间的通信。

 /**
 * 管道流其实也是操作内存中的数组实现的。具体可查看源码。多用于线程之间的通信。
 * Created by lyyz on 2018/5/24.
 */
public class PipedEg {
    public static void main(String[] args) throws IOException {
        //管道流可以实现两个线程之间,二进制数据的传输。
        TestPipedInputStream testPipedInputStream = new TestPipedInputStream();
        TestPipedOutputStream testPipedOutputStream = new TestPipedOutputStream();
        //将管道连接
        testPipedOutputStream.getPipedOutputStream().connect(testPipedInputStream.getPipedInputStream());
        Thread th1 = new Thread(testPipedInputStream);
        Thread th2 = new Thread(testPipedOutputStream);
        th1.start();
        th2.start();
    }

}
class TestPipedInputStream implements Runnable {
    private PipedInputStream pipedInputStream;

    public TestPipedInputStream() {
        pipedInputStream = new PipedInputStream();
    }

    public PipedInputStream getPipedInputStream() {
        return pipedInputStream;
    }

    @Override
    public void run() {
        try {
            byte[] bytes = new byte[1024];
            int len = pipedInputStream.read(bytes);
            System.out.println(len);
            System.out.println(new String(bytes, "utf-8"));
            pipedInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class TestPipedOutputStream implements Runnable {
    private PipedOutputStream pipedOutputStream;

    public TestPipedOutputStream() {
        pipedOutputStream = new PipedOutputStream();
    }

    public PipedOutputStream getPipedOutputStream() {
        return pipedOutputStream;
    }

    @Override
    public void run() {
        try {
            pipedOutputStream.write("testPipedOutputStream 管道测试".getBytes("utf-8"));
            pipedOutputStream.flush();
            pipedOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.4缓冲流

/**
     * 用了BufferedInputStream后你每次读取都是从缓冲区里拷贝数据,在后你再读,缓冲区没东西了就调IO从数据源读到缓冲区,然后你再从缓冲区读。
     * 如果你自己建立的数组大小和缓冲区大小一样,根本就没起到缓冲作用。
     * 当你程序的数组小于缓冲区的大小的时候才会起到缓冲作用。比如是byte[] b=new byte[2048];,
     * 你要读的数据是1G,那么你要调512次IO,假设一次1s,就512s,但如果用BufferedInputStream,
     * 你每从缓冲区读取4(8192/2048=4)次才调用一次IO(假设访问内存一次0.1s),总共要128次
     * ,就128s,加上总的从缓冲区拷贝数据的时间(512*0.1=51.2s),128+51.2=179.2。
     * 这里用0.1s和1s来体现IO很耗时
     */
    public static void testBufferedInputStream(){
        try {
            File file = new File("testfile.txt");
            FileInputStream fileInputStream = new FileInputStream(file);
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
            //每次读取时1024  而默认缓冲区的大小是1024*8  缓冲起到作用  
            byte[] inbytes = new byte[1024];
            System.out.println(file.length());
            int count = 1;
            while(true){
                System.out.println("count====================================="+count);
                int len=bufferedInputStream.read(inbytes);
                System.out.println("len = ======================================================="+len);
                System.out.println(new String(inbytes,"utf-8"));
                ++count;
                if(len==-1)
                    break;
            }

            fileInputStream.close();
            bufferedInputStream.close();
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            bufferedOutputStream.write("testBufferedInputStream 测试".getBytes("utf-8"));
            bufferedOutputStream.flush();
            bufferedOutputStream.close();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.5 ObjectInputStream

ObjectInputStream,OjbectOutputStream 通常用做序列化反序列化应用。它是处理流。

public static void testObjectInputStream(){
        try {
            Cat cat = new Cat("12","波斯猫");
            File file = new File("object.txt");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
            objectOutputStream.writeObject(cat);
            objectOutputStream.flush();
            objectOutputStream.close();
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            Object object= objectInputStream.readObject();
            Cat inCat = (Cat)object;
            System.out.println(inCat.getId()+"=="+inCat.getName());
            objectInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    class Cat implements Serializable{
    // 可序列化对象的版本
    private static final long serialVersionUID = 1L;
    private String id;
    private String name;

    public Cat(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

3.总结

Java IO流有很多类,学习起来很费时间。但是抓住几个常用的类学习,看看源码,把源码理解清楚,思路还是挺清晰的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值