流、Java IO流、OkHttp3

流的理解

在计算机科学中,流(Stream)是数据处理的一种抽象模型。数据流可以被看作是数据项的序列,这些数据项可以逐个地被处理,而无需一次性将所有数据项加载到内存中。

流的概念常用于输入/输出(I/O)系统,如文件读写、网络通信等。例如,当我们从文件中读取数据时,可以将文件看作是一个输入流,我们可以逐个地读取文件中的数据项,而无需一次性将整个文件加载到内存中。同样,当我们向文件中写入数据时,可以将文件看作是一个输出流,我们可以逐个地向文件中写入数据项。

在gRPC中,流式RPC允许我们在一个RPC调用中发送或接收多个消息。例如,服务器流式RPC允许服务端连续发送多个响应给客户端,客户端可以在任何时候从这个“流”中读取响应。同样,客户端流式RPC允许客户端连续发送多个请求给服务端,服务端可以在任何时候从这个“流”中读取请求。

总的来说,流提供了一种处理大量数据的有效方式,特别是对于那些无法一次性加载到内存中的大数据集。

流怎么处理大数据量?

流(Stream)处理大数据集的方式主要是通过逐个处理数据项,而不是一次性加载整个数据集到内存中。这种方式可以有效地处理大数据集,因为它不需要大量的内存,并且可以立即开始处理数据,而不需要等待整个数据集加载完成。

流的处理过程通常包括以下几个步骤:

  1. 读取数据:从数据源(如文件、网络等)读取一部分数据到内存中。这部分数据通常被称为缓冲区(Buffer)。

  2. 处理数据:在内存中处理缓冲区中的数据。处理方式取决于具体的应用,可能包括解析、转换、过滤、聚合等操作。

  3. 输出数据:将处理后的数据输出到目标地方(如文件、网络等)。如果数据需要进一步处理,也可以输出到另一个流中。

  4. 重复步骤1-3,直到所有数据都被处理。

流的处理过程可以是同步的,也可以是异步的。在同步模式下,每个步骤都是按顺序执行的,即必须等待一个步骤完成后才能开始下一个步骤。在异步模式下,多个步骤可以同时执行,例如,可以在读取数据的同时处理数据,这可以进一步提高处理效率。

流的底层实现取决于具体的系统和语言。在许多系统和语言中,流是通过操作系统的文件或网络I/O接口实现的。例如,在Unix和Linux系统中,流可以通过文件描述符(File Descriptor)实现,文件描述符是一个用于表示打开的文件或网络连接的整数。在Java和Python等语言中,流可以通过类似于InputStream和OutputStream的类实现,这些类提供了读取和写入数据的方法。

流每次处理的数据量大小

流每次读取数据的数量,也就是缓冲区的大小,取决于具体的应用和系统。缓冲区的大小可以影响到数据处理的效率和内存使用。

如果缓冲区太小,那么流可能需要频繁地从数据源读取数据,这可能导致大量的I/O操作,从而降低处理效率。另一方面,如果缓冲区太大,那么可能会占用大量的内存,这可能导致内存不足的问题。

在许多系统和语言中,缓冲区的大小通常可以配置。例如,在Java的BufferedReader类中,可以在构造函数中指定缓冲区的大小。在Python的open函数中,可以通过buffering参数指定缓冲区的大小。

在实际应用中,缓冲区的大小通常需要根据数据的特性和系统的性能进行调整。例如,如果数据源是一个慢速的网络连接,那么可能需要使用一个较大的缓冲区来减少I/O操作。如果数据是大量的小文件,那么可能需要使用一个较小的缓冲区来减少内存使用。

Java IO流

Java的IO流是实现输入/输出的基础,在Java中把不同的输入/输出源里的有序数据抽象表述为“流”(Stream),简化了输入输出处理。流是指一连串的流动的字符,是以先进先出的方式发送和接收数据的通道,通过流的方式允许Java程序使用相同的方式来访问不同的输入/输出源。Java把所有的流操作相关的类都放在java.io包中,用来实现输入/输出功能。

Java IO流的分类

流向来分,流可分为输入流和输出流:

  • 输入流:只能从中读取数据,不能向其写入数据,主要由InputStream和Reader作为基类
  • 输出流:只能向其写入数据,不能从中读取数据,主要由OutputStream和Writer作为基类

所操作的数据单元可分为字节流和字符流:

  • 字节流:操作的数据单元是8位的字节,主要由InputStream类和OutputStream作为基类
  • 字符流:操作的数据单元是16位的字符,主要由Reader和Writer作为基类

输入流与输出流

流分为输入流和输出流,输入/输出流是相对于计算机内存来说的,如果数据输入到内存,则称为输入流,如果是从内存中输出则称为输出流。Java的输入流主要由InputStream类和Reader类作为基类而输出流则主要由OutputStream类和Write类作为基类。构造流对象时往往会和数据源(如文件)联系起来。

输入/输出流又分为字节流和字符流两种形式。

InputStream类常用方法

方法说明
int read()从输入流中读取下一个字节数据
int read(byte[] b)从输入流中读取数据,并将数据存储在缓冲区数组b中,返回实际读取的字节数
int read(byte[] b,int off,int len)从输入流中读取最多len长度的字节,保存到字节数组b中保存的位置从off开始
void close()关闭输入流
  • InputStream类的常用子类有FileInputStream,用于从文件中读取数据

OutputStream类常用方法:

方法说明
int write()将指定的字节数据写入到此输出流中
int write(byte[] buf)将数组buf中的所有字节写入到此输出流中
int write(byte[] buf,int off,int len)将字节数组中从偏移量off开始的长度为len的字节数据输出到输出流中
void close()关闭输出流
  • OutputStream类的常用子类有FileOutputStream,用于向文件中写入数据

字节流和字符流

字节流是8位通用字节流,其基本单位是字节。字节流的基类是InputStream类和OutputStream类,它们是抽象类。

字符流是16位Unicode字符流,基本单位是Unicode字符。字符流最适合用来处理字符串和文本,因为它们支持国际上的大多数字符集和语言。字符流的基类是Reader类和Writer类,它们也是抽象类。

Reader类常用方法

方法说明
int read()从输入流中读取单个字符
int read(char[] b)从输入流中读取最多c.length个字符,保存到字符数组c中,返回实际读取的字符数
int read(char[] b,int off,int len)从输入流中读取最多length个字符,保存到字符数组c中,保存的位置从off位置开始,返回实际读取的字节数
void close()关闭字符输入流
  • Reader类的常用子类为BufferedReader,接受Reader对象作为参数,并对其添加字符缓冲器

Writer类常用方法

方法说明
int write(String str)将str字符串里包含的字符输出到指定的输出流中
int write(String str,int off,int len)将str字符串里从off位置开始,长度为len的多个字符输出到输出流中
void close()关闭输出流
void flush()刷新输出流
void close()关闭字符输入流
  • Writer类的常用子类为BufferedWriter,用于将数据缓冲到字符输出流

注:

  • 在操作字节流与字符流时有一个区别,字符流在操作时使用了缓冲区(内部存储器),而字节流在操作时直接操作文件,不会使用缓冲区。
  • 所有的这些方法在出现错误时都会抛出IOException异常

OkHttp3

OkHttp3是一个开源的HTTP客户端,用于发送网络请求。它的API设计简洁,易于使用,同时提供了强大的功能,如连接池、GZIP压缩、HTTP/2支持等。

使用OkHttp3发送GET请求

以下是一个使用OkHttp3发送GET请求的基本示例:

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpExample {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("http://www.example.com")
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println(response.body().string());
        }
    }
}

在这个示例中,我们首先创建了一个OkHttpClient实例,然后创建了一个Request实例,指定了请求的URL。然后,我们调用OkHttpClient的newCall方法创建一个Call实例,然后调用execute方法发送请求并获取响应。最后,我们打印出响应的内容。

使用OkHttp3发送POST请求

OkHttp3还支持其他类型的请求(默认是GET),如POST、PUT、DELETE等,可以通过Request.Builder的method方法或者对应的快捷方法(如post、put)来设置。例如,以下是一个发送POST请求的示例:

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.MediaType;

public class OkHttpPostExample {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, "{\"name\":\"John Doe\"}");

        Request request = new Request.Builder()
                .url("http://www.example.com")
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println(response.body().string());
        }
    }
}

在这个示例中,我们首先创建了一个RequestBody实例,指定了请求的内容类型和内容。然后,我们在创建Request实例时调用了post方法,将RequestBody实例传入,从而创建了一个POST请求。其他步骤与前面的示例相同。

使用OkHttp3需要注意的点

在生产环境中使用OkHttp3时,有几个关键点需要注意:

  1. 错误处理:网络请求可能会失败,你需要准备好处理这些失败的情况。例如,你可能需要重新尝试请求,或者在用户界面上显示错误消息。

  2. 超时设置:OkHttp的默认超时可能不适合你的应用。你应该根据你的应用的需求和网络条件来设置合适的超时。

  3. OkHttpClient实例的复用:OkHttpClient实例是设计用来被复用的,而不是为每个请求创建一个新的实例。复用OkHttpClient实例可以提高性能,因为它可以共享同一个连接池和线程池。

  4. 线程管理:OkHttp的请求是同步的,也就是说,当你调用execute方法时,它会阻塞当前线程直到请求完成。如果你在主线程中执行网络请求,这可能会导致应用界面冻结。你应该在后台线程中执行网络请求,或者使用OkHttp的异步API。

  5. 安全性:如果你的应用需要处理敏感信息,如用户密码或者信用卡信息,你需要确保你的请求是通过HTTPS发送的,而不是HTTP。你也需要验证你的服务器的SSL证书,以防止中间人攻击。

  6. 关闭响应:当你处理完响应后,你需要关闭它,以释放网络资源。你可以通过调用Response的close方法来关闭响应,或者使用Java 7的try-with-resources语句来自动关闭响应。

  7. 请求/响应日志:在生产环境中,可能需要记录请求和响应的详细信息,以便于问题排查。可以通过实现和设置OkHttp的Interceptor来完成。

  8. 处理大文件或流媒体:如果你需要下载大文件或流媒体,你应该使用流的方式来处理响应,而不是一次性加载整个响应到内存中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的 Java OkHttp3 工具类的示例代码: ```java import okhttp3.*; import java.io.IOException; import java.util.Map; public class OkHttpUtil { private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); private static final OkHttpClient client = new OkHttpClient(); /** * GET 请求 * * @param url 请求地址 * @return 响应结果字符串 * @throws IOException 请求失败抛出异常 */ public static String get(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } /** * POST 请求 * * @param url 请求地址 * @param params 请求参数 * @return 响应结果字符串 * @throws IOException 请求失败抛出异常 */ public static String post(String url, Map<String, String> params) throws IOException { FormBody.Builder formBuilder = new FormBody.Builder(); for (Map.Entry<String, String> entry : params.entrySet()) { formBuilder.add(entry.getKey(), entry.getValue()); } RequestBody requestBody = formBuilder.build(); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } /** * POST 请求,请求体为 JSON 格式 * * @param url 请求地址 * @param json 请求体 JSON 字符串 * @return 响应结果字符串 * @throws IOException 请求失败抛出异常 */ public static String postJson(String url, String json) throws IOException { RequestBody requestBody = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } } ``` 使用示例: ```java public class Main { public static void main(String[] args) throws IOException { // GET 请求 System.out.println(OkHttpUtil.get("https://www.baidu.com")); // POST 请求,表单参数 Map<String, String> params = new HashMap<>(); params.put("name", "张三"); params.put("age", "18"); System.out.println(OkHttpUtil.post("http://localhost:8080/user", params)); // POST 请求,JSON 参数 String json = "{\"name\":\"张三\",\"age\":18}"; System.out.println(OkHttpUtil.postJson("http://localhost:8080/user", json)); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值