国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

流(stream)是怎么一回事

MangoGoing / 1621人閱讀

摘要:文件流,系統(tǒng)標(biāo)準(zhǔn)輸入輸出流,標(biāo)準(zhǔn)錯(cuò)誤流,還有一開始提到的流,還有一些后臺(tái)技術(shù)如對(duì)請(qǐng)求響應(yīng)流的抽象,都可以見到流的概念。語(yǔ)言的庫(kù)中定義了打開文件流時(shí)必須指定的集中打開方式,表示用于讀取,用于寫入,用于讀寫。

—— 對(duì)這個(gè)問題的思考來源于前幾天對(duì) Java Socket 編程的嘗試,TCP 協(xié)議要求建立一個(gè) Socket 連接(著名的三次握手)之后才能進(jìn)行通信,而連接雙方進(jìn)行數(shù)據(jù)的發(fā)送與接受,都是通過對(duì)輸入輸出的機(jī)制來完成的。

流的概念

流作為概念應(yīng)該是語(yǔ)言無關(guān)的。文件IO流,Unix系統(tǒng)標(biāo)準(zhǔn)輸入輸出流,標(biāo)準(zhǔn)錯(cuò)誤流(stdin, stdout, stderr),還有一開始提到的 TCP 流,還有一些 Web 后臺(tái)技術(shù)(如Nodejs)對(duì)HTTP請(qǐng)求/響應(yīng)流的抽象,都可以見到流的概念。

K&R 在 C Programming Language 書中提到流是這樣定義的:

流 (stream) 是與磁盤或其它外圍設(shè)備關(guān)聯(lián)的數(shù)據(jù)的源或目的地。

可以把流理解成是對(duì)程序外界交換數(shù)據(jù)的一種抽象,這里的外界限定是有必要的,通常不會(huì)把程序內(nèi)部的數(shù)據(jù)流動(dòng)抽象為流,畢竟在程序內(nèi)部,數(shù)據(jù)流動(dòng)是由函數(shù)調(diào)用、返回來完成的。而當(dāng)我們使用三個(gè)標(biāo)準(zhǔn)IO流時(shí),我們關(guān)心的是怎樣通過它們與外界交互;當(dāng)我們使用文件流時(shí),我們關(guān)心的是將內(nèi)存中的數(shù)據(jù)持久化到磁盤文件中(或從磁盤中讀數(shù)據(jù)導(dǎo)內(nèi)存)。

于是數(shù)據(jù)從 A 處“流”向 B 處,可以類比像水流一樣從高處流向低處。在水流動(dòng)的過程中,作為最基本物理組成單位的水分子是不變的,相應(yīng)的數(shù)據(jù)流也有它最小的組成單位。在不同的編程語(yǔ)言中,這個(gè)最小單位通常是字節(jié)流(二進(jìn)制流)中的字節(jié),或者字符流(文本流)中的字符。

——但不會(huì)是其他數(shù)據(jù)類型,就像我們從來沒聽說過數(shù)字流?,或者浮點(diǎn)數(shù)流,甚至數(shù)組流?

因?yàn)樽止?jié)是計(jì)算機(jī)保存數(shù)據(jù)的最終形式,而字符是其它數(shù)據(jù)結(jié)構(gòu)序列化后的表現(xiàn)形式,也是人可以閱讀的形式。與外界的交互需要這些通用的格式。不關(guān)心數(shù)據(jù)的內(nèi)容,只需要完整地傳輸原始數(shù)據(jù)時(shí),考慮字節(jié)流即可;關(guān)心傳輸字符和字符串時(shí),就需要對(duì)字符流進(jìn)行操作,stdio.h頭文件里那一大坨輸入輸出函數(shù)就是干這個(gè)的。比如fgetc(FILE *stream)從文本流中讀入一個(gè)字符。

另一方面,根據(jù)數(shù)據(jù)流動(dòng)的方向,可以再抽象出輸出流和輸入流的概念。從程序內(nèi)部到外部的流向是輸出流,從程序外部到內(nèi)部的流向是輸入流。

C 語(yǔ)言的stdio.h庫(kù)中定義了打開文件流時(shí)必須指定的集中打開方式,"r"表示用于讀取,"w"用于寫入,"r+"用于讀寫。類似地,Java 語(yǔ)言的java.io包中包含了InputStream, OutputStream 明確區(qū)分的輸入流類和輸出流類,并且二者都是抽象類,意味著必須根據(jù)需要使用它們各自的子類進(jìn)行實(shí)例化。

通過流操作實(shí)現(xiàn)(最)簡(jiǎn)單的文件拷貝

根據(jù)實(shí)際的代碼可以幫助理解stream,下面是一段用C語(yǔ)言標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)的最簡(jiǎn)單的文件拷貝功能。

出于學(xué)習(xí)目的,這段代碼偷懶沒有任何容錯(cuò)功能,是典型的反面教材, 不過 whatever 了,不信你真拿去編譯一下,是真的可以完整拷貝文件!除了不能拷貝目錄,不能拷貝不存在的文件,不能拷貝文件權(quán)限,不能漏掉目的文件名或者路徑,不能靈活處理文件軟鏈接硬鏈接。等等等等blahblah(所以其實(shí)連看上去很簡(jiǎn)單的cp程序也是要有一大坨因素要考慮和支持的(啊跑題了

// mini_cp.c
#include 
#define BUFFER_SIZE 512

int main(int argc, char *argv[])
{ 
  // 從命令行參數(shù)中獲得 SOURCE 和 DES 文件流
  FILE *src = fopen(argv[1], "rb");
  FILE *des = fopen(argv[2], "wb");
  
  long int num;
  
  // buffer 是讀寫的緩沖數(shù)組
  char buffer[BUFFER_SIZE];

  while(!feof(src)) {
    num = fread(buffer, sizeof(char), BUFFER_SIZE, src);
    fwrite(buffer, sizeof(char), num, des);
  }

  fclose(src);
  fclose(des);

  return 0;
}

這個(gè)自制的mini_cp程序不難理解,核心的邏輯可以分解為三個(gè)步驟:

打開源文件流FILE *src和目的文件流FILE *des

循環(huán)執(zhí)行 { 每次從src流讀取最多512字節(jié)的數(shù)據(jù) => 并寫入des流 } 直到源文件讀取結(jié)束

關(guān)閉文件流

核心邏輯是非常清晰明了的,這樣的邏輯也是流操作的普遍原理,嘗試其他語(yǔ)言的實(shí)現(xiàn),其實(shí)都已經(jīng)大同小異,往往都少不了一個(gè)緩沖區(qū)的概念(或?qū)ο螅?/p>

來看一下 Java 版本的同等實(shí)現(xiàn):

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Copy {
    
    private static final int BUFFER_SIZE = 512;

    public static void main(String[] args) throws IOException {
        
        File srcFile = new File(args[0]);
        File desFile = new File(args[1]);

        int recvBytesSize;
        byte[] buffer = new byte[BUFFER_SIZE];

        FileInputStream in = new FileInputStream(srcFile);
        FileOutputStream out = new FileOutputStream(desFile);

        while((recvBytesSize = in.read(buffer)) != -1) {
            out.write(buffer, 0, recvBytesSize);
        }

        in.close();
        out.close();

    }
}

面向?qū)ο笪陡鼭?del>(代碼更冗長(zhǎng))了有木有?但也正是因?yàn)槊嫦驅(qū)ο螅琂ava 把理論上的 stream 抽象為類,讓我們直接獲得類的實(shí)例(即對(duì)象),從而對(duì)對(duì)象進(jìn)行操作。還是挺不賴的是吧,雖然代碼更長(zhǎng)了沒錯(cuò),但是更 OO 啊~

寫到這里已經(jīng)能回答流基本是怎么一回事了,那么最后順便再來放一段拷貝程序的ruby實(shí)現(xiàn);

require "fileutils"
FileUtils.cp("SOURCE.txt", "DEST.txt")

哈?

嗯。

... That"s why we love Ruby...(逃。。。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/64758.html

相關(guān)文章

  • 《Java8實(shí)戰(zhàn)》-第六章讀書筆記(用收集數(shù)據(jù)-01)

    摘要:收集器用作高級(jí)歸約剛剛的結(jié)論又引出了優(yōu)秀的函數(shù)式設(shè)計(jì)的另一個(gè)好處更易復(fù)合和重用。更具體地說,對(duì)流調(diào)用方法將對(duì)流中的元素觸發(fā)一個(gè)歸約操作由來參數(shù)化。另一個(gè)常見的返回單個(gè)值的歸約操作是對(duì)流中對(duì)象的一個(gè)數(shù)值字段求和。 用流收集數(shù)據(jù) 我們?cè)谇耙徽轮袑W(xué)到,流可以用類似于數(shù)據(jù)庫(kù)的操作幫助你處理集合。你可以把Java 8的流看作花哨又懶惰的數(shù)據(jù)集迭代器。它們支持兩種類型的操作:中間操作(如 filt...

    EscapedDog 評(píng)論0 收藏0
  • Flink 靈魂兩百問,這誰頂?shù)米。?/b>

    摘要:由于配置流是從關(guān)系型數(shù)據(jù)庫(kù)中讀取,速度較慢,導(dǎo)致實(shí)時(shí)數(shù)據(jù)流流入數(shù)據(jù)的時(shí)候,配置信息還未發(fā)送,這樣會(huì)導(dǎo)致有些實(shí)時(shí)數(shù)據(jù)讀取不到配置信息。從數(shù)據(jù)庫(kù)中解析出來,再去統(tǒng)計(jì)近兩周占比。 Flink 學(xué)習(xí) https://github.com/zhisheng17/flink-learning 麻煩路過的各位親給這個(gè)項(xiàng)目點(diǎn)個(gè) star,太不易了,寫了這么多,算是對(duì)我堅(jiān)持下來的一種鼓勵(lì)吧! showI...

    Guakin_Huang 評(píng)論0 收藏0
  • Java8學(xué)習(xí)小記

    摘要:但有一個(gè)限制它們不能修改定義的方法的局部變量的內(nèi)容。如前所述,這種限制存在的原因在于局部變量保存在棧上,并且隱式表示它們僅限于其所在線程。 2014年,Oracle發(fā)布了Java8新版本。對(duì)于Java來說,這顯然是一個(gè)具有里程碑意義的版本。尤其是那函數(shù)式編程的功能,避開了Java那煩瑣的語(yǔ)法所帶來的麻煩。 這可以算是一篇Java8的學(xué)習(xí)筆記。將Java8一些常見的一些特性作了一個(gè)概要的...

    CHENGKANG 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<