C # sử dụng luồng


116

Đối với tôi, suối rất bí ẩn. Tôi không biết khi nào sử dụng luồng nào và cách sử dụng chúng. Ai đó có thể giải thích cho tôi cách sử dụng luồng không?

Nếu tôi hiểu đúng, có ba loại luồng:

  • stream
  • read stream
  • write stream

Điều này có chính xác? Và, ví dụ, sự khác biệt giữa a Memorystreamvà a là FileStreamgì?


13
bạn có thể muốn kiểm tra stackoverflow.com/questions/507747/...
Preets

3
Lấy một mảng byte và sau đó tạo một trình bao bọc cho nó ( Stream) để hiển thị một số phương thức hữu ích như đọc, ghi và thay đổi vị trí. Bây giờ bạn có thể tạo các lớp dựa trên kho lưu trữ sao lưu của chúng (FileStream, MemoryStream) kế thừa Streamvà xây dựng dựa trên chức năng đó dựa trên lưu trữ sao lưu cụ thể.
The Muffin Man

Câu trả lời:


80

Một dòng là một đối tượng sử dụng để truyền dữ liệu. Có một lớp dòng chung System.IO.Stream, từ đó tất cả các lớp dòng khác trong .NET đều được dẫn xuất. CácStream lớp giao dịch với byte.

Các lớp dòng cụ thể được sử dụng để xử lý các loại dữ liệu khác ngoài byte. Ví dụ:

  • Các FileStreamlớp học được sử dụng khi các nguồn bên ngoài là một tập tin
  • MemoryStream được sử dụng để lưu trữ dữ liệu trong bộ nhớ
  • System.Net.Sockets.NetworkStream xử lý dữ liệu mạng

Các luồng người đọc / người viết chẳng hạn như StreamReaderStreamWriterkhông phải là luồng - chúng không có nguồn gốc từ đó System.IO.Stream, chúng được thiết kế để giúp ghi và đọc dữ liệu từ và đến luồng!


3
Vì vậy, nếu tôi hiểu đúng, luồng chứa dữ liệu và không làm gì với nó. Các lớp 'trợ giúp' của người đọc và người viết có thể xử lý (thao tác) dữ liệu trong luồng không?
Martijn 10/09/09

9
Không, Stream không phải là vùng chứa dữ liệu, nó được sử dụng để truyền dữ liệu, ví dụ: FileStream truyền dữ liệu từ byte [] sang tệp phisical, NetworkStream chuyển byte [] bằng socket. Các lớp Reader Writer là các lớp trợ giúp để ghi và đọc từ luồng, ví dụ: StreamReader có thể được sử dụng để đọc từ chuỗi Luồng chứ không phải byte []. nếu bạn cung cấp FileStream như một tham số, nó sẽ đọc từ File, nếu NetworkStream từ socket.
Arsen Mkrtchyan 10/09/09

Ngoài ra, StreamReader và StreamWriter là để đọc và ghi các luồng TEXT (ký tự).
1c1cle

1
có một bài viết hay để giúp bạn hiểu về MemoryStream. codeproject.com/Articles/832387/…
Jiaji Li

2
@ người dùng420667. câu hỏi hay. Trong cả hai trường hợp AudioStream và TemperatureStream, chúng rất có thể sẽ là BinaryStream cho trình điều khiển được liên kết với thiết bị. Hoặc, bạn có thể tạo một Dòng tùy chỉnh được xây dựng riêng cho giao diện.
1c1cle,

62

Để mở rộng một chút về các câu trả lời khác ở đây và giúp giải thích nhiều mã ví dụ mà bạn sẽ thấy rải rác, hầu hết thời gian bạn không đọc và ghi trực tiếp vào luồng. Luồng là một phương tiện cấp thấp để truyền dữ liệu.

Bạn sẽ nhận thấy rằng các hàm để đọc và ghi đều được định hướng theo byte, ví dụ như WriteByte (). Không có chức năng nào để xử lý số nguyên, chuỗi, v.v. Điều này làm cho luồng rất có mục đích chung, nhưng ít đơn giản hơn để làm việc với nếu bạn chỉ muốn chuyển văn bản.

Tuy nhiên, .NET cung cấp các lớp chuyển đổi giữa các kiểu gốc và giao diện luồng cấp thấp và chuyển dữ liệu đến hoặc từ luồng cho bạn. Một số lớp đáng chú ý như vậy là:

StreamWriter // Badly named. Should be TextWriter.
StreamReader // Badly named. Should be TextReader.
BinaryWriter
BinaryReader

Để sử dụng các lớp này, trước tiên bạn có được luồng của mình, sau đó bạn tạo một trong các lớp ở trên và liên kết nó với luồng. Ví dụ

MemoryStream memoryStream = new MemoryStream();
StreamWriter myStreamWriter = new StreamWriter(memoryStream);

StreamReader và StreamWriter chuyển đổi giữa các kiểu gốc và các biểu diễn chuỗi của chúng, sau đó chuyển các chuỗi đến và từ luồng dưới dạng byte. Vì thế

myStreamWriter.Write(123);

sẽ viết "123" (ba ký tự '1', '2' rồi đến '3') vào luồng. Nếu bạn đang xử lý các tệp văn bản (ví dụ: html), StreamReader và StreamWriter là các lớp bạn sẽ sử dụng.

Trong khi

myBinaryWriter.Write(123);

sẽ viết bốn byte đại diện cho giá trị số nguyên 32-bit 123 (0x7B, 0x00, 0x00, 0x00). Nếu bạn đang xử lý các tệp nhị phân hoặc các giao thức mạng, BinaryReader và BinaryWriter là những gì bạn có thể sử dụng. (Nếu bạn đang trao đổi dữ liệu với mạng hoặc các hệ thống khác, bạn cần lưu ý đến tính bền vững , nhưng đó là một bài đăng khác.)


Các lớp bộ điều hợp StreamWriter và Reader bị đặt tên rất tệ. Cảm ơn vì đã đề cập đến điều đó. Làm thế nào mà họ đã nghĩ ra cái tên này vẫn còn gây ngạc nhiên cho tôi.
Tarik

Ngoài ra, ngay cả các lớp người viết và người đọc nhị phân cũng bị đặt tên xấu.
Tarik

22

Luồng rất tốt để xử lý lượng lớn dữ liệu. Khi tải tất cả dữ liệu vào bộ nhớ cùng một lúc là không thực tế, bạn có thể mở nó dưới dạng một luồng và làm việc với những phần nhỏ của nó.


1
Rất thích xem một ví dụ về những gì bạn vừa nói "làm việc với những phần nhỏ của nó".
Jenna Leaf

2
Luồng cũng tốt cho một lượng nhỏ dữ liệu. Nếu một lập trình viên C # muốn thao tác nội dung của một tệp, họ phải sử dụng các luồng, bất kể số lượng dữ liệu là bao nhiêu. Tuyên bố tương tự cũng đúng với các luồng mạng. Được cho là, nếu lập trình viên viết mã là một ngôn ngữ cấp thấp hơn như C, thì có thể ghi các ký tự hoặc byte trực tiếp vào đĩa hoặc ổ cắm, nhưng ngay cả đối với một lượng nhỏ dữ liệu, nó sẽ tốn thời gian và dễ bị lỗi.
1c1cle,

10

Luồng chỉ là một sự trừu tượng hóa (hoặc một trình bao bọc) trên một physicalluồng byte. Đây physicalsuối được gọi là base stream. Vì vậy, luôn có một luồng cơ sở mà qua đó trình bao bọc luồng được tạo và do đó trình bao bọc được đặt tên theo loại luồng cơ sở FileStream, tức làMemoryStream v.v.

Ưu điểm của trình bao bọc luồng là bạn có được một api hợp nhất để tương tác với các luồng thuộc bất kỳ loại cơ bản nào, usb, filev.v.

Tại sao bạn lại coi dữ liệu là luồng - vì các phần dữ liệu được tải theo yêu cầu, chúng tôi có thể kiểm tra / xử lý dữ liệu dưới dạng các phần chứ không phải tải toàn bộ dữ liệu vào bộ nhớ. Đây là cách hầu hết các chương trình xử lý với các tệp lớn, chẳng hạn như mã hóa tệp hình ảnh hệ điều hành.


4

Chỉ có một loại cơ bản Stream. Tuy nhiên trong các trường hợp khác nhau, một số thành viên sẽ ném một ngoại lệ khi được gọi vì trong bối cảnh đó, hoạt động không khả dụng.

Ví dụ a MemoryStreamchỉ đơn giản là một cách để di chuyển các byte vào và ra khỏi một đoạn bộ nhớ. Do đó, bạn có thể gọi là Đọc và Viết trên đó.

Mặt khác, a FileStreamcho phép bạn đọc hoặc ghi (hoặc cả hai) từ / vào một tệp. Việc bạn thực sự có thể Đọc hoặc Ghi phụ thuộc vào cách tệp được mở. Bạn không thể Ghi vào tệp nếu bạn chỉ mở nó để truy cập Đọc.


3

Tôi sẽ bắt đầu bằng cách đọc các luồng trên MSDN: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Memorystream và FileStream là các luồng được sử dụng để làm việc với bộ nhớ thô và Tệp tương ứng ...


Cảm ơn các liên kết. Tôi thích rằng "Bạn có thể duyệt qua mã nguồn trực tuyến, tải xuống tài liệu tham khảo để xem ngoại tuyến và xem qua các nguồn (bao gồm các bản vá và cập nhật) trong quá trình gỡ lỗi". Tính năng này cung cấp một cấp độ hiểu biết mới.
David

1

Tôi sẽ không gọi đó là những loại luồng khác nhau. Lớp Luồng có các thuộc tính CanRead và CanWrite cho bạn biết liệu luồng cụ thể có thể được đọc và ghi vào.

Sự khác biệt chính giữa các lớp luồng khác nhau (chẳng hạn như MemoryStream so với FileStream) là nơi lưu trữ sao lưu - nơi dữ liệu được đọc từ hoặc nơi được ghi vào. Rõ ràng là từ cái tên. MemoryStream chỉ lưu trữ dữ liệu trong bộ nhớ, FileStream được sao lưu bởi một tệp trên đĩa, NetworkStream đọc dữ liệu từ mạng, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.