什么是内存流和文件流?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是内存流和文件流?相关的知识,希望对你有一定的参考价值。

它们是用来做什么的?怎么用?哪位大虾知道的请帮帮忙,感谢……

文件流 FileStream继承与Stream类,一个FileStream类的实例实际上代表一个文件流,使用FileStream类可以对文件系统上是文件进行读取、写入、打开和关闭操作。与iostream、sStream共同作为头文件构成IO标准库。

内存流 MemoryStream表示的是保存在内存中的数据流,由内存流封装的数据可以在内存中直接访问。内存一般用于暂时缓存数据以降低应用程序对临时缓冲区和临时文件的需要。

引入内存流是因为内存流和字节数组虽然都位于程序缓冲区,但是具有不同特性。内存流相对于字节数组而言,具有流特有的特性,并且容量可自动增长,在数据加密以及对长度不定的数据进行缓存等场合,使用内存流比较方便。

扩展资料:

MemoryStream有多种构造函数如下:

1、public MemoryStream();该构造函数初始分配的容量大小为0,随着数据的不断写入,其容量可以不断地自动扩展。

2、public MemoryStream(byte[] buffer);根据字节数组buffer初始化,实例的容量大小规定为字节数组的长度。

3、public MemoryStream(int capacity);容量固定为capacity。

参考技术A 什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。
下面,笔者通过四个实例:EXE文件加密器、电子贺卡、自制OICQ和网络屏幕传输来说明Delphi编程中 "流 "的利用。这些例子中的一些技巧曾经是很多软件的秘密而不公开的,现在大家可以无偿的直接引用其中的代码了。
"万丈高楼平地起 ",在分析实例之前,我们先来了解一下流的基本概念和函数,只有在理解了这些基本的东西后我们才能进行下一步。请务必认真领会这些基本方法。当然,如果你对它们已经很熟悉了,则可以跳过这一步。

一、Delphi中流的基本概念及函数声明
在Delphi中,所有流对象的基类为TStream类,其中定义了所有流的共同属性和方法。
TStream类中定义的属性介绍如下:
1、Size:此属性以字节返回流中数据大小。
2、Position:此属性控制流中存取指针的位置。
Tstream中定义的虚方法有四个:
1、Read:此方法实现将数据从流中读出。函数原形为:
Function Read(var Buffer;Count:Longint):Longint;virtual;abstract;
参数Buffer为数据读出时放置的缓冲区,Count为需要读出的数据的字节数,该方法返回值为实际读出的字节数,它可以小于或等于Count中指定的值。
2、Write:此方法实现将数据写入流中。函数原形为:
Function Write(var Buffer;Count:Longint):Longint;virtual;abstract;
参数Buffer为将要写入流中的数据的缓冲区,Count为数据的长度字节数,该方法返回值为实际写入流中的字节数。
3、Seek:此方法实现流中读取指针的移动。函数原形为:
Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract;
参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下:
soFromBeginning:Offset为移动后指针距离数据开始的位置。此时Offset必须大于或者等于零。
soFromCurrent:Offset为移动后指针与当前指针的相对位置。
soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。该方法返回值为移动后指针的位置。
4、Setsize:此方法实现改变数据的大小。函数原形为:
Function Setsize(NewSize:Longint);virtual;
另外,TStream类中还定义了几个静态方法:
1、ReadBuffer:此方法的作用是从流中当前位置读取数据。函数原形为:
Procedure ReadBuffer(var Buffer;Count:Longint);
参数的定义跟上面的Read相同。注意:当读取的数据字节数与需要读取的字节数不相同时,将产生EReadError异常。
2、WriteBuffer:此方法的作用是在当前位置向流写入数据。函数原形为:
Procedure WriteBuffer(var Buffer;Count:Longint);
参数的定义跟上面的Write相同。注意:当写入的数据字节数与需要写入的字节数不相同时,将产生EWriteError异常。
3、CopyFrom:此方法的作用是从其它流中拷贝数据流。函数原形为:
Function CopyFrom(Source:TStream;Count:Longint):Longint;
参数Source为提供数据的流,Count为拷贝的数据字节数。当Count大于0时,CopyFrom从Source参数的当前位置拷贝Count个字节的数据;当Count等于0时,CopyFrom设置Source参数的Position属性为0,然后拷贝Source的所有数据;
TStream还有其它派生类,其中最常用的是TFileStream类。使用TFileStream类来存取文件,首先要建立一个实例。声明如下:
constructor Create(const Filename:string;Mode:Word);
Filename为文件名(包括路径),参数Mode为打开文件的方式,它包括文件的打开模式和共享模式,其可能的取值和意义如下:

打开模式:
fmCreate :用指定的文件名建立文件,如果文件已经存在则打开它。
fmOpenRead :以只读方式打开指定文件
fmOpenWrite :以只写方式打开指定文件
fmOpenReadWrite:以写写方式打开指定文件
共享模式:
fmShareCompat :共享模式与FCBs兼容
fmShareExclusive:不允许别的程序以任何方式打开该文件
fmShareDenyWrite:不允许别的程序以写方式打开该文件
fmShareDenyRead :不允许别的程序以读方式打开该文件
fmShareDenyNone :别的程序可以以任何方式打开该文件

TStream还有一个派生类TMemoryStream,实际应用中用的次数也非常频繁。它叫内存流,就是说在内存中建立一个流对象。它的基本方法和函数跟上面是一样的。
好了,有了上面的基础后,我们就可以开始我们的编程之行了。本回答被提问者采纳

内存流和文件流的区别

【中文标题】内存流和文件流的区别【英文标题】:difference between memory stream and filestream 【发布时间】:2011-12-30 17:02:57 【问题描述】:

在序列化过程中,我们可以使用内存流或文件流。

这两者之间的基本区别是什么?内存流是什么意思?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serilization

    class Program
    
        static void Main(string[] args)
        
            MemoryStream aStream = new MemoryStream();
            BinaryFormatter aBinaryFormat = new BinaryFormatter();
            aBinaryFormat.Serialize(aStream, person);
            aStream.Close();
        
    

【问题讨论】:

【参考方案1】:

关于stream本身,一般来说,这意味着当你将一个内容放入stream(内存)时,它不会将任何数据源(文件,db...)的所有内容都放入你正在使用,记忆。与例如数组或缓冲区相反,您将所有内容放入内存。在stream 中,您会得到一个chunk 例如。文件到内存中。当你到达块的末尾时,stream 从文件获取下一个块到内存。这一切都发生在低级背景中,而您只是在迭代 stream。这就是为什么它被称为stream

【讨论】:

【参考方案2】:

这里的其他答案很棒,但我认为对蒸汽服务的目的进行非常高层次的了解可能会有用。在下面的解释中进行了一些简化,但希望这能传达出这个想法:

什么是流?

流实际上是两个地方之间的数据流,它是管道而不是管道的内容。

一个不好的类比开始

想象一个海水淡化厂(吸收海水、去除盐分并将清洁的饮用水输出到水网):

海水淡化厂无法一次性去除所有海洋中的盐分(我们也不希望它……咸水鱼会住在哪里?),所以我们有:

SeaStream 一次将一定量的水吸入植物。 那个SeaStream连接到DesalinationStream去盐分 DesalinationStream 的输出连接到DrinkingWaterNetworkStream,将现在的无盐水输出到饮用水源。

好的,那这和电脑有什么关系?

一次移动所有大文件可能会有问题

在计算中,我们经常希望在两个位置之间移动数据,例如从外部硬盘驱动器到数据库中的二进制字段(使用另一个答案中给出的示例)。我们可以通过将文件中的所有数据从位置 A 复制到计算机内存并从那里复制到位置 B 来做到这一点,但是如果文件很大或者源或目标可能不可靠,那么一次移动整个文件可能要么不可行,要么不明智。

例如,假设我们要将 U 盘上的一个大文件移动到数据库中的某个字段。我们可以使用“System.IO.File”对象将整个文件检索到计算机的内存中,然后使用数据库连接将该文件传递到数据库中。

但是,这可能会带来问题,如果文件大于计算机的可用 RAM 怎么办?现在文件可能会被缓存到硬盘上,这很慢,甚至可能会减慢计算机的速度。

同样,如果数据源不可靠,例如使用缓慢且不稳定的 WiFi 连接从网络驱动器复制文件?尝试一次性复制一个大文件可能会令人恼火,因为您获得了一半的文件,然后连接断开,您必须重新开始,否则它可能会再次失败。

最好是拆分文件,一次移动一块

因此,与其一次获取整个文件,不如一次检索一个文件,然后一次将每个文件传递到目标文件。这就是 Stream 所做的,这就是您提到的两种不同类型的流的来源:

我们可以使用FileStream 一次从文件中检索数据 和数据库 API 可以提供一个MemoryStream 端点,我们可以一次写入一个片段。 我们将这两个“管道”连接在一起,以将文件片段从文件传输到数据库。

即使文件不是太大而不能保存在 RAM 中,如果没有流,我们仍然会执行一些我们不需要的数字或读/写操作。我们正在执行的阶段是:

    从磁盘检索数据(慢) 写入计算机内存中的 File 对象(快一点) 从计算机内存中的 File 对象读取(再次更快) 写入数据库(可能很慢,因为管道末端可能有一个旋转的磁盘硬盘驱动器)

Streams 允许我们在概念上取消中间两个阶段,而不是一次将整个文件拖到计算机内存中,我们将操作的输出用于检索数据并将其直接通过管道传递给操作以传递数据到数据库中。

流的其他好处

像这样将数据的检索与数据的写入分开还允许我们在检索数据和传递数据之间执行操作。例如,我们可以添加一个加密阶段,或者我们可以将传入数据写入不止一种类型的输出流(例如,写入 FileStream 和 NetworkStream)。

Streams 还允许我们编写代码,以便在传输中途失败时恢复操作。通过跟踪我们移动的片段数量,如果传输失败(例如,如果网络连接断开),我们可以从我们收到最后一个片段的点重新启动 Stream(这是offsetBeginRead 方法)。

【讨论】:

谢谢! “数据库 API 可能提供 MemoryStream 端点”是我试图理解使用 MemoryStream 写入控制台的说明。【参考方案3】:

在我看来,序列化内存中的对象几乎没有任何用处。当您想将对象保存在磁盘上时,您需要对其进行序列化。通常,序列化是从对象(在内存中)到磁盘完成,而反序列化是从保存的序列化对象(在磁盘上)到对象(在内存中)完成。

因此,大多数时候,您希望序列化到磁盘,因此您使用 Filestream 进行序列化。

【讨论】:

【参考方案4】:

在这个主题上有一段痛苦的经历,这就是我发现的。如果需要性能,您应该将文件流的内容复制到内存流。我必须处理 144 个文件的内容,每个文件 528kbytes 并将结果呈现给用户。大约花了 250 秒。 (!!!!)。当我只是将每个文件流的内容复制到内存流(CopyTo 方法)而不做任何更改时,时间下降到大约 32 秒。请注意,每次将一个流复制到另一个流时,该流都会附加到目标流的末尾,因此您可能需要在复制到它之前“倒回”它。希望能帮助到你。

【讨论】:

痛苦的经历?!?当然,在 RAM 中操作文件将比在磁盘上操作文件更快。你期待什么? ;-)【参考方案5】:

流是字节的表示。这两个类都派生自 Stream 类,根据定义,它是抽象的。

顾名思义,FileStream 读取和写入文件,而 MemoryStream 读取和写入内存。所以它与流的存储位置有关。

现在取决于您打算如何使用这两种方法。例如:假设您想从数据库中读取二进制数据,您将使用 MemoryStream。但是,如果您想读取系统上的文件,则需要使用 FileStream。

MemoryStream 的一个快速优势是无需在应用程序中创建临时缓冲区和文件。

【讨论】:

既然对象已经在内存中了,为什么还要为序列化分配内存流呢? 因为内存流将对象作为字节序列来操作,而不是作为其逻辑程序的“意义”。 @tudor:因为我是.net 的新手,你能简要解释一下吗? @Raghav55:一个对象可以简化为一个字节序列,对吗?在您的程序逻辑中,该对象具有含义,例如持有姓名、地​​址等信息的人员。这就是该对象在您的程序中的显示方式。当您将其序列化为内存流时,它会减少为没有意义的字节流。它仅被存储,但对您的程序逻辑没有实际价值。 我正在从数据库中读取大量日期并希望将其作为 csv 文件发送回用户,但我使用内存流的内存不足...我相信我'将不得不将其转换为文件流以获得更多空间。【参考方案6】:

内存流通过内存缓冲区处理数据。文件流处理磁盘上的文件。

【讨论】:

嗨克里斯托弗,想在这里问一个问题。那么这是否意味着如果我使用内存流,模式是“不是从文件产生的数据(例如fprintf(memory_buf, "hello"))内存缓冲区过程数据”,而对于基于文件的流,模式是“数据位于/产生/来自磁盘内存缓冲区过程数据”?【参考方案7】:

当文件流从文件中读取时,内存流可用于读取映射到计算机内部存储器 (RAM) 中的数据。您基本上是从内存中读取/写入字节流。

【讨论】:

在对大数据进行序列化时哪个更好?如果序列化数据很大并且可用内存很小。当我们使用内存流时,这种情况会发生什么? 如果你的数据超过了可用内存,它最终会开始分页到磁盘。这很糟糕,因为整个系统的性能会下降。在这种情况下,最好只流式传输到文件。【参考方案8】:

在最简单的形式中,MemoryStream 将数据写入内存,而 FileStream 将数据写入文件。

通常,如果我需要流,我会使用 MemoryStream,但我不希望任何东西撞击磁盘,并且在将文件写入磁盘时使用 FileStream。

【讨论】:

以上是关于什么是内存流和文件流?的主要内容,如果未能解决你的问题,请参考以下文章

输入流与输出流

nodeJS文件流和事件

java _io_图片到内存(字节数组),字节数组到文件,练习文件流和字节数组流

C++学习摘要之九:C++流和文件流

流概述与字节流输入输出

字符流和字节流的区别