java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java IO流 Guava

一文带你了解Java中IO流与Guava的使用

作者:指北君

Java为我们提供了非常多的操作IO的接口与类,帮助开发者实现不同源间的数据传输,比如硬盘文件、网络传输、应用调用间的数据交互与传递。今天我们来简单了解下Java中的流 以及在Guava工具包中,针对IO操作做了什么样的封装与设计

Guava IO

日常系统交互中,文件的上传下载都是常见的,一般我们会通过jdk提供的IO操作库帮助我们实现。IO指的是数据相对当前操作程序的入与出,将数据通过 输出流从程序输出,或者通过输入流将数据(从文件、网络、数据等)写入到程序,这里的IO指的是基于流作为载体进行数据传输。如果把数据比作合理的水,河就是IO流,也是数据的载体。

Java为我们提供了非常多的操作IO的接口与类,帮助开发者实现不同源间的数据传输,比如硬盘文件、网络传输、应用调用间的数据交互与传递。今天我们来简单了解下Java中的流 以及在Guava工具包中,针对IO操作做了什么样的封装与设计。

分类

在java.io包中有非常多的IO相关接口,我们可以根据流的输出类型、处理对象以及功能将其分为以下几种类型:

按数据流向

按操作单位

区分:

字节流一般以Stream结尾 字符流一般以Reader或Writer结尾

按操作方式

按功能

常用的流

操作文件的

java.io.FileinputStream/FileOutputStream java.io.FileReader/FileWriter

通用的字节流

java.io.InputStreamReader/outputStreamWriter

缓冲流

java.io.BufferedReader/BufferedWriter java.io.BufferedInputStream/BufferedOutputStream

数据流

java.io.DataInpoutStream/DataOutputStream

功能型的

java.io.PrintWriter/PrintStream

对象序列化相关的

java.io.ObjectInputStream/ObjectOutputStream

可见,提供的IO对象基本都是成对出现的,用以完成数据的输入输出,实现程序与外部载体间的数据交换

示例

下面我们通过一些常用示例来看看IO的使用的场景与使用方法:

文件复制

    @Test
    public void copyByBytes() throws IOException {
        String root = FileTests.class.getResource("/").getPath();

        FileInputStream fis = new FileInputStream(new File(root,"/start.bat"));
        FileOutputStream fos = new FileOutputStream(root+"/out2.bat");

        byte[] buff = new byte[100];

        int b;
        while ( (b = fis.read(buff))!=-1 ){
            fos.write(buff, 0, b);
        }
        // close
    }

文件合并

@Test
    public void mergeFiles() throws IOException {
        File file1 = new File("E:\\_projects\\sucls\\blog\\my_study\\guava\\guava-io\\src\\test\\java\\com\\sucls\\blog\\guava\\io\\category\\FileTests.java");
        File file2 = new File("E:\\_projects\\sucls\\blog\\my_study\\guava\\guava-io\\src\\test\\java\\com\\sucls\\blog\\guava\\io\\category\\StreamTests.java");

        Enumeration<InputStream> ins = Collections.enumeration(Arrays.asList(
                new FileInputStream(file1),
                new FileInputStream(file2)
        ));

        SequenceInputStream sequenceInputStream = new SequenceInputStream(ins);

        FileOutputStream fos = new FileOutputStream(root+"/out4");

        byte[] buff = new byte[100];

        int read; // 真实读取到的字节数
        while ( (read = sequenceInputStream.read(buff)) !=-1){
            fos.write(buff, 0, read);
        }

        fos.close();
    }

读取文件内容为字符串

    @Test
    public void readStringFromFile() throws IOException {
        FileReader fileReader = new FileReader(new File(this.getClass().getResource("/").getPath(),"/start.bat"));

        StringBuilder stringBuilder = new StringBuilder();

        int i;
        while ( (i = fileReader.read())!=-1 ){
            stringBuilder.append( (char)i ); // 按字符读取
        }

        System.out.println( stringBuilder ); // 文件内容
    }

字节数组转换成流

    @Test
    public void bytesToStream(){
        byte [] data = new byte[1024]; // 来源于其他数据源

        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        int v;
        while ( (v=inputStream.read())!=-1 ){
            outputStream.write(v);
        }

        System.out.println( Arrays.toString( outputStream.toByteArray() ));
    }

对象序列化与反序列化

@Test
    public void objectToFile() throws IOException {

        Person person = new Person();
        person.setName("张三").setAge(25);

        String root = FileTests.class.getResource("/").getPath();

        FileOutputStream fos = new FileOutputStream(new File(root,"/person"));
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeObject(person);
    }

    @Test
    public void fileToObject() throws IOException, ClassNotFoundException {
        String root = FileTests.class.getResource("/").getPath();

        FileInputStream fis = new FileInputStream(new File(root,"/person"));
        ObjectInputStream ois = new ObjectInputStream(fis);

        Person person = (Person) ois.readObject();
        System.out.println( person );
    }

流的转换 将字节流转换成字符流来操作,同样以文件复制为例

    @Test
    public void copyByBuffer() throws IOException {
        String root = FileTests.class.getResource("/").getPath();

        FileInputStream fis = new FileInputStream(new File(root,"/start.bat"));
        InputStreamReader isr = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(isr);

        FileOutputStream fos = new FileOutputStream(root+"/out3.bat");
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);

        String line;
        while ( (line = br.readLine())!=null ){
            bw.append(line);
            bw.newLine();
            bw.flush();
        }

        // close
    }

关于流的操作非常多,像包括网络通信中、音视频文件处理、流合并等等

Guava中的IO

关于IO的内容并不复杂,上面的那些例子在很多工具库中基本都会提供对应的API方便开发者调用,今天主要看下Guava IO模块针对流的操作提供了什么样的 封装

Files

提供对文件快捷读写方法 其中主要提供了ByteSource、ByteSink、CharSource、CharSink 4个类,分别对应按字节的读写与按字符的读写,

 /**
     * 文件复制
     */
    @Test
    public void copy() throws IOException {
        File from = new File(root,"from");
        File to = new File(root,"to");
        Files.copy(from,to);
    }

    /**
     * 文件移动
     */
    @Test
    public void move() throws IOException {
        File from = new File(root,"from");
        File to = new File(root,"to");
        Files.move(from,to);
    }

    /**
     * 按行读取文件
     * @throws IOException
     */
    @Test
    public void readLines() throws IOException {
        File dest = new File(root,"start.bat");
        List<String> lines = Files.readLines(dest, Charset.defaultCharset());
        lines.forEach(System.out::println);
    }

    /**
     * 写入文件
     * @throws IOException
     */
    @Test
    public void writeToFile() throws IOException {
        File dest = new File(root,"demo.txt");
        Files.write("hello world!".getBytes(Charset.defaultCharset()), dest);
    }

    /**
     * 修改文件更新时间
     * @throws IOException
     */
    @Test
    public void touch() throws IOException {
        File dest = new File(root,"demo.txt");
        Files.touch(dest);
    }

    /**
     * 文件的零拷贝
     * @throws IOException
     */
    @Test
    public void map() throws IOException, URISyntaxException {
        File from = new File(root,"from");
        File to = new File(root,"to");
        Files.touch(to);
        
        MappedByteBuffer fromBuff = Files.map(from, MapMode.READ_ONLY, 1024);
        // =>
        FileChannel channel = FileChannel.open(Paths.get(to.toURI()), StandardOpenOption.WRITE);

        channel.write(fromBuff);

        channel.close();
    }

    /**
     * 读文件为字节数组
     * @throws IOException
     */
    @Test
    public void fileAndBytes() throws IOException {
        File dest = new File(root,"start.bat");
        ByteSource byteSource = Files.asByteSource(dest);
        byte[] bytes = byteSource.read();
        System.out.println( bytes );

        // 字节写入文件,实现复制
        File target = new File(root, "start2.bat");
        ByteSink byteSink = Files.asByteSink(target);
        byteSink.write(bytes);
    }

    @Test
    public void wrapper(){
        File dest = new File(root,"start.bat");
        // 作为字节读
        Files.asByteSource(dest);
        // 作为字节写
        Files.asByteSink(dest);

        // 作为字符读
        Files.asCharSource(dest, Charset.defaultCharset());
        // 作为字符写
        Files.asCharSink(dest, Charset.defaultCharset());
    }

其他

管道流

PipedOutputStream  PipedInputStream 实现多线程间的数据通信;类似生产消费者模式

@Test
    public void pipe() throws IOException {
        PipedOutputStream pipedOutputStream = new PipedOutputStream();
        PipedInputStream pipedInputStream = new PipedInputStream();
        pipedOutputStream.connect(pipedInputStream);

        new Thread(()->{
            while (true){
                String date = new Date().toString();
                try {
                    pipedOutputStream.write( date.getBytes(StandardCharsets.UTF_8) );
                    pipedOutputStream.flush();
                    TimeUnit.SECONDS.sleep(2);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
        
        new Thread(()->{
            while (true){
                byte [] buff = new byte[1024];
                try {
                    int read = pipedInputStream.read(buff);
                    TimeUnit.SECONDS.sleep(4);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println( new String(buff) );
            }
        }).start();
    }

结束语

在任何编程语言中,数据的IO都是比较常见并相当重要的。Guava作为工具型类库,主要是帮助开发者封装常用、重复的操作,开放出简介的API,不仅能让让代码更加整洁, 同时对开发出稳健程序也是比不可少的。

到此这篇关于一文带你了解Java中IO流与Guava的使用的文章就介绍到这了,更多相关Java IO流 Guava内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文