Поток (програмиране)

от Уикипедия, свободната енциклопедия
Вижте пояснителната страница за други значения на Поток.

Пример за последователност от процеси общуващи чрез различни потоци от данни

Потокът (на английски: stream) представлява строго подредена последователност от цифрово кодирани сигнали, използвани за предаване или приемане на данни от и на различни устройства.[1] Потоците не предоставят произволен достъп до данните си, а само последователен, т.е може да манипулираме данните само в реда, в който те пристигат от потока.

Потоците са основното средство за обмяна на информация в компютърния свят. Чрез тях програмите отварят файлове в компютъра или се осъществяват мрежови комуникации между компютри. Работата на почти всички периферни устройства (USB, звукови карти, принтери, скенери и други) може да се осъществи през абстракцията на потоците. За да прочетем или запишем нещо във файл, трябва да отворим поток към него. Модерните сайтове функционират благодарение на потоците. Така наречения видео стрийминг, който сайтовете предлагат, представлява поточно четене на обемни мултимедийни файлове. Поточното аудио и видео позволява възпроизвеждане преди цялостното изтегляне на файла.

Видове потоци[редактиране | редактиране на кода]

В зависимост от типа данни, с които потоците работят, те могат да бъдат разделени на две големи групи: двоични потоци, които работят с бинарни данни, и текстови потоци – работещи с поредица от символи.

Двоични потоци[редактиране | редактиране на кода]

Двоичните потоци работят с бинарни (двоични) данни. Това ги прави универсални и те могат да бъдат използвани за четене на информация от всякакви файлове (изображения, аудио- и мултимедийни файлове, текстови файлове и т.н.).

Класът BinaryWriter позволява записването в поток на данни от примитивни типове във вид на двоични стойности в специфично кодиране. Той има един основен метод – Write(...), който позволява записва не на всякакви примитивни типове данни – числа, символи, булеви стойности, масиви, низове и др. Класът BinaryReader позволява четенето на данни от примитивни типове, записани с помощта на BinaryWriter. Основните му методи ни позволяват да четем символ, масив от символи, цели числа, числа с плаваща запетая и др. Подобно на предходните два класа, обект от този клас може да получим, извиквайки конструктора му.

Текстови потоци[редактиране | редактиране на кода]

Текстовите потоци са много подобни на двоичните, но работят само с текстови данни. Добър избор са за работа с текстови файлове, но са неизползваеми при работа с каквито и да е бинарни файлове.

В операционната система файлът винаги е поредица от байтове, а дали ще се разглежда като текстови или бинарен зависи от интерпретацията на байтовете. Съответно, писането на един текстови ред в текстови файл или поток означава записване на бинарната репрезентация на текста.

Основни операции с потоци[редактиране | редактиране на кода]

Създаване[редактиране | редактиране на кода]

Свързване на потока с източник на данни, механизъм за пренос на данни или друг поток. Например, при файлов поток се подава името на файла и режимът, в който ще се отваря (за четене, за писане или за четене и писане едновременно).

Пример на C#:

using System.IO; // инициализиране на библиотека

// създаване на поток за четене от съществуващ файл.
FileStream fileStream = new FileStream(@"c:\file.txt",FileMode.Open);

Четене[редактиране | редактиране на кода]

Четенето представлява последователно извличане на данни от текущата позиция на потока. То е блокираща операция и ако отсрещната страна не е изпратила данни докато се прави опит за четене или изпратените данни още не са пристигнали, може да се получи забавяне – от няколко милисекунди до часове, дни или по-голямо. Например, при четене от мрежов поток, данните могат да се забавят по мрежата или отсрещната страна може изобщо да не изпрати никакви данни.

Пример на C#:

using System;
using System.IO;

// създаване на поток за четене от файл
StreamReader sr = new StreamReader("TestFile.txt"));

using (sr)
{
   string testText = sr.ReadToEnd(); // създава променлива от тип низ със съдържанието на файла
   Console.WriteLine(testText);      // печата на конзолата съдържанието на низа
}

Писане[редактиране | редактиране на кода]

При писане се изпращат данни в потока по специфичен начин. Записът се извършва от текущата позиция на потока. Последният потенциално може да е блокираща операция и да се забави докато данните поемат по своя път. Например, ако се изпращат обемни данни по мрежов поток, операцията може да се забави докато данните отпътуват по мрежата.

Пример на C#:

using System;
using System.IO;

// създаване на поток за записване във файл

StreamWriter sw = new StreamWriter(@"c:/WriteFile.txt");
  using (sw)
  {
      // създаване на масив от низове с няколко имена
      string[] names = new string[] { "Ivan", "Pesho", "Gosho", "Misho" };

      using (sw)
      {
         for (int i = 0; i < names.Length; i++)
         {
             sw.WriteLine(names[i]); // записване на всеки елемент от масива на нов ред в текстов файл
         }
      }
   }

Позициониране[редактиране | редактиране на кода]

Преместване на текущата позиция на потока. Преместването се извършва спрямо текуща позиция, като можем да позиционираме спрямо текуща позиция, спрямо началото на потока или спрямо края на потока. Премест­ване можем да извършваме единствено в потоци, които поддържат пози­циониране. Например файловите потоци обикновено поддържат позицио­ниране, докато мрежовите не поддържат.

Пример на C#:

using System;
using System.IO;

public abstract long Seek(
	long offset,
	SeekOrigin origin
)

// C++ код
public:
virtual long long Seek(
	long long offset,
	SeekOrigin origin
) abstract

// F# код
abstract Seek:
        offset:int64 *
        origin:SeekOrigin -> int64

// VB код 'Declaration
Public MustOverride Function Seek (_
	offset As Long, _
	origin As SeekOrigin _
) As Long

Затваряне[редактиране | редактиране на кода]

Приключваме работата с потока и освобождаваме ресурсите, заети от него. Затварянето трябва да се извършва възможно най-рано след при­ключване на работата с потока, защото ресурс, отворен от един потребител, обикновено не може да се ползва от останалите потребители (в това число от други програми на същия компютър, които се изпълняват паралелно на нашата програма).

Пример на C#:

using System;
using System.IO;

FileStream fileStream = new FileStream(@"c:\file.txt", FileMode.Open);
try
{
  // четене или писане от файл
}
finally
{
  // затваряне на потока с метода Stream.Close()
  fileStream.Close();
}
  • Автоматично затваряне в c#

В горния пример е показано, как след приключване на работа с поток или с файл се извиква метода Close() за задължителното затваряне на потока или файла. Често се случва въвеждането на Close() да бъде пропуснато от невнимание, което излага на опасност файла, с който работим. C# предлага конструкция за автоматично затваряне:

using (<stream object>) {...}

Използването на using гарантира, че след излизането от тялото, автоматично ще се извика метода Close().

Пример на C#:

using System;
using System.IO;

FileStream fileStream = new FileStream(@"c:\file.txt", FileMode.Open);

using(fileStream // обекта)
{
   try
   {
      // четене или писане от файл
   }
   finally
   {
      // няма нужда от използването на метода Stream.Close()
      Console.WriteLine("The stream closed automatically.");
   }
}

Вижте също[редактиране | редактиране на кода]

Източници[редактиране | редактиране на кода]

  1. Federal Standard 1037C data stream // NTIA. Посетен на 19 юли 2013. (на английски)

Литература[редактиране | редактиране на кода]