Android文件流-I/O,nio和oKio

简介: Android文件流-I/O,nio和oKio

1681484922173.png

学习目标

  • java传统io如何使用
  • 非阻塞 nio 是怎么回事
  • okio 的优势与使用

I/O 是什么?

  • 程序内部和外部进⾏行行数据交互的过程,就叫输入输出。
  • 程序内部是谁?内存
  • 程序外部是谁?
  • 一般来说是两类:本地⽂文件和⽹络。
  • 也有别的情况,⽐如你和别的程序做交互,和你交互的程序也属于外部,但一般来说,就是⽂件和网络这么两种。
  • 从⽂件里或者从网络上读数据到内存里,就叫输入;从内存里写到文件里或者发送到网 络上,就叫输出

java传统io: 流

从文件读数据到内存里面,方便操作网络数据和本地文件,操作更加灵活了,所有的操作都是利用String来代替

熟悉java io 的基本操作

就是 24_io.txt 如果没有 就会帮忙创建,如果有就不会创建,这个就是用java io做的一个基本操作

1681484963378.png

 try {
 // 输出流的管子
            final FileOutputStream fileOutputStream = new FileOutputStream("./24_io/24_io.txt");
            fileOutputStream.write('a');
            fileOutputStream.write('b');
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

不是直接操作文件,而是直接操作流,通过一根管子,插到这个文件上,然后对这个流进行操作,这样可以对不同的外部对象使用统一的操作形式,不管是往一个文件还是网络还是其他形式,我都是创造一个String的格式,然后往这个String 去写 或者 去存 然后去读 这个String,相当于在程序内部和外界之间搭建了一个桥梁 ,我虽然把处理单件事件变复杂了,比如:我一辈子都处理文件,或者一辈子处理网络 ,把这个变复杂了,但是整体上有一个一致性,所以扩展性变更好了,由于这个扩展性,他做的事情也变多了,不止是可以读写文件,还可以和网络交互,而且还有其他形式可以和网络操作,也可以通过其他扩展的String来操作

java 文件的 读取操作

资源的持有会消耗内存,所以我们在不需要这些资源的时候我们需要释放这些资源,所谓的释放就是把文件关闭,把文件的关闭本质就是把流给舍弃调,java 7 以下我们需要在 finally处理如下:

  InputStream sFileInputStream = null;
        try {
            sFileInputStream = new FileInputStream("./24_io/24_io.txt");
            System.out.println((char) sFileInputStream.read());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sFileInputStream != null) {
                try {
                    sFileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

java 7 以及以上 在 try () 处理即可,自动关流

 try (InputStream sFileInputStream = new FileInputStream("./24_io/24_io.txt")) {
            System.out.println((char) sFileInputStream.read());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

所有的流都实现了 Closeable,所有的 Closeable 如果在try 里面做初始化 都会被自动关闭

public abstract class InputStream implements Closeable {}

怎么和文件进行互操作,怎么把文件转换成字符?

  try (InputStream sFileInputStream = new FileInputStream("./24_io/24_io.txt")) {
            Reader inputStreamReader = new InputStreamReader(sFileInputStream);
            final BufferedReader bufferedInputStream = new BufferedReader(inputStreamReader);
            System.out.println(bufferedInputStream.readLine());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

readLine的本身的意义不是一行读,他会额外读一些内容到自己内部,它本身的意思是增加缓冲,他会额外读一些内容到缓冲

1681484828583.png

从BufferReader 源码可以看出:

private static int defaultCharbufferSize = 8192

默认可以读 8192 个字节,为了提高性能,我们必须设置一个默认值

Buffer 写数据 其实是在缓冲里面放数据,所以写完之后记得及时 flush 将目标东西刷新到目标区

      try (OutputStream sFileInputStream = new FileOutputStream("./24_io/24_io.txt")) {
            final BufferedOutputStream inputStream = new BufferedOutputStream(sFileInputStream);
            inputStream.write('a');
            inputStream.write('b');
            inputStream.write('M');
            inputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }

如: outPutStream 没有 flush 不会写成功的,那么为什么Buffer不能自动刷新呢?


因为缓冲是为了做效率, 和文件操作性能会比较低,所以尽量减少这样的操作,把频率降低,把多次io给合起来,这样才能提高性能呢.Buffer 会导致输出不同步这是必然的事情


同样在 try 里面 做数据包装操作,也会自动刷新缓存到目标区

     try (OutputStream sFileInputStream = new FileOutputStream("./24_io/24_io.txt"); final BufferedOutputStream inputStream = new BufferedOutputStream(sFileInputStream)) {
            inputStream.write('a');
            inputStream.write('b');
            inputStream.write('M');
         } catch (Exception e) {
            e.printStackTrace();
        }

文件复制

java没有文件复制的功能的,那么怎么做文件复制呢,我们要做的是把文件数据一个一个搬

  try (InputStream fileInputStream = new FileInputStream("./24_io/24_io.txt");
             OutputStream outputstream = new FileOutputStream("./24_io/text_copy.txt")) {
            final byte[] bytes = new byte[1024];
            int read = 0;
            while ((read = fileInputStream.read(bytes)) != -1) {
                outputstream.write(bytes, 0, read);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

如果想提高性能 我们可以加 Buffer

这就是Java的 I/O 原理,核心就是:内存与外界的交互,你可以用 inputStream 和 outPutStream 做对接

Java I/O 作⽤

和外界做数据交互

Socket 和 ServerSocket 之间的网络交互

和文件交互是 java i/o 里面 和 网络进行交互的,就像和文件交互 用 File 比如: 我做个服务器


        try {
            final ServerSocket serverSocket = new ServerSocket(8080);
            final Socket socket = serverSocket.accept();
            final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            while (true) {
                final String data = reader.readLine();
                writer.write("你给我输入了: " + data);
                writer.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

nio 与传统 io的区别

  • 传统io用的是插管道的方式 
  • nio 的 Channel 是双向的,传统io是单向的
        try {
            final RandomAccessFile file = new RandomAccessFile("./24_io/24_io.txt", "r");
            final FileChannel channel = file.getChannel();
            final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            channel.read(byteBuffer);
            byteBuffer.flip();
            System.out.println(Charset.defaultCharset().decode(byteBuffer));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }  
  • nio 也用到了缓冲 buffer nio 可以被操作的,nio的Buffer是强制使用的,不好用
        try {
            final ServerSocketChannel channel = ServerSocketChannel.open();
            channel.bind(new InetSocketAddress(8080));
            channel.configureBlocking(false);
            final SocketChannel socketChannel = channel.accept();
            final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            while (socketChannel.read(byteBuffer) != -1) {
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

为什么 非阻塞式 nio 设置 configureBlocking 开关 会报NullException?

Exception in thread "main" java.lang.NullPointerException

因为 channel.accept() 没有拿到数据,socketChannel 为 null,还没有发起请求就设置 false了

okio

okio 作为一个外部对象作为输入输出,okio是独立形式存在的.

 try (BufferedSource  source = Okio.buffer(Okio.source(new File("./24_io/24_io.txt")) )) {
            final Buffer buffer = new Buffer();
            source.read(buffer, 1024);
            System.out.println(buffer.readUtf8());
        } catch (Exception e) {
            e.printStackTrace();
        }

okio 和 传统 io 作交互

   final Buffer buffer = new Buffer();
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(buffer.outputStream()));
             BufferedReader bufferReader = new BufferedReader(new InputStreamReader(buffer.inputStream()))) {
            writer.write("哈哈哈哈");
            writer.flush();
            System.out.println("read: " + bufferReader.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }

Okio 实现文件下载

    private void downloadFile(@NonNull Uri inputUri, @Nullable Uri outputUri) throws NullPointerException, IOException {
        Log.d(TAG, "downloadFile");
        if (outputUri == null) {
            throw new NullPointerException("Output Uri is null - cannot download image");
        }
        OkHttpClient client = new OkHttpClient();
        BufferedSource source = null;
        Sink sink = null;
        Response response = null;
        try {
            Request request = new Request.Builder()
                    .url(inputUri.toString())
                    .build();
            response = client.newCall(request).execute();
            source = response.body().source();
            OutputStream outputStream = mContext.getContentResolver().openOutputStream(outputUri);
            if (outputStream != null) {
                sink = Okio.sink(outputStream);
                source.readAll(sink);
            } else {
                throw new NullPointerException("OutputStream for given output Uri is null");
            }
        } finally {
            BitmapLoadUtils.close(source);
            BitmapLoadUtils.close(sink);
            if (response != null) {
                BitmapLoadUtils.close(response.body());
            }
            client.dispatcher().cancelAll();
            // swap uris, because input image was downloaded to the output destination
            // (cropped image will override it later)
            mInputUri = mOutputUri;
        }
    }



相关文章
|
Android开发
Android 开发引用 okio 依赖之后无法运行main方法的坑
Android 开发引用 okio 依赖之后无法运行main方法的坑
106 1
|
监控 Java API
Android IO 框架 Okio 的实现原理,如何检测超时?
在上一篇文章里,我们聊到了 Square 开源的 I/O 框架 Okio 的三个优势:精简且全面的 API、基于共享的缓冲区设计以及超时机制。前两个优势已经分析过了,今天我们来分析 Okio 的超时检测机制。
173 0
|
缓存 Java API
Android IO 框架 Okio 的实现原理,到底哪里 OK?
今天,我们来讨论一个 Square 开源的 I/O 框架 Okio,我们最开始接触到 Okio 框架还是源于 Square 家的 OkHttp 网络框架。那么,OkHttp 为什么要使用 Okio,它相比于 Java 原生 IO 有什么区别和优势?今天我们就围绕这些问题展开。
204 0
|
20天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
22天前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
22 1
|
7天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
34 19
|
20天前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
7天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
31 14
|
10天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
8天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
18 5