Как я могу писать в файл вместо массива байтов в памяти?

На данный момент у меня есть этот код, который получает информацию по сети, сохраняет ее в массив байтов в памяти, а затем записывает ее через FileStream.

 StreamReader reader = new StreamReader(tcpClient.GetStream());

  // first message is file size
         string cmdFileSize = reader.ReadLine();

  // first message is filename
        string cmdFileName = reader.ReadLine();

        int length = Convert.ToInt32(cmdFileSize);
        byte[] buffer = new byte[length];
        int received = 0;
        int read = 0;
        int size = 1024;
        int remaining = 0;


   while (received < length)
        {
            remaining = length - received;
            if (remaining < size)
            {
                size = remaining;
            }

            read = tcpClient.GetStream().Read(buffer, received, size);
            received += read;
            if (read < size)
            {
                break;
            }
        }    

После этого "буфер" записывается в файл через FileStream. Это работает хорошо, но когда у меня есть большие файлы, очевидно, что этот объем памяти занимает место. Я хотел бы передавать эти файлы прямо на диск, а не записывать их в оперативную память, а затем перезаписывать их на жесткий диск.

Как я мог это сделать?


person Lewis Cianci    schedule 08.10.2015    source источник
comment
вы смотрели на Метод TcpClient.GetStream в MSDN   -  person MethodMan    schedule 08.10.2015
comment
проверьте это, если вы хотите вместо этого писать в файл hostprojects.net/snippets/cs/76/   -  person MethodMan    schedule 08.10.2015
comment
@MethodMan Да, вы можете использовать StreamReader для этого, но я думаю, что базовый код в любом случае может в конечном итоге использовать буфер.   -  person Viru    schedule 08.10.2015
comment
вы можете попробовать что-то вроде этого, чтобы убедиться, что для больших файлов вы можете умножить размер 1024 на что-то вроде этого byte[] buffer = new byte[16 * 1024];   -  person MethodMan    schedule 08.10.2015
comment
Я использую метод, который делает что-то подобное при чтении, например, из ResponseStream.. хотите ли вы увидеть метод, который я использую, вам просто нужно немного изменить его, чтобы он работал для вашего варианта использования..   -  person MethodMan    schedule 08.10.2015
comment
То, что ищет OP, - это способ записи данных непосредственно в файл вместо любого буфера, в чем я сомневаюсь.   -  person Viru    schedule 08.10.2015
comment
@MethodMan на самом деле это именно тот код, на который я ссылаюсь, ха-ха. Ведь должен же быть способ? Я знаю, что это сильно отличается, но если вы копируете файл через общий ресурс SMB, файл записывается на диск без предварительного сохранения его в памяти.   -  person Lewis Cianci    schedule 08.10.2015
comment
@viru Я был бы счастлив использовать буфер, если бы буфер мог быть меньше (например, с удовольствием использовал бы буфер размером 10 МБ, и чтобы буфер каким-то образом добавлялся к файлу после заполнения 10 МБ).   -  person Lewis Cianci    schedule 08.10.2015
comment
@LewisCianci, у меня есть метод, который может работать для того, что вы делаете или пытаетесь сделать.. вы хотели бы увидеть метод, который я создал, чтобы сделать что-то подобное..??   -  person MethodMan    schedule 08.10.2015
comment
@MethodMan С удовольствием, пожалуйста :)   -  person Lewis Cianci    schedule 08.10.2015
comment
@LewisCianci, где у меня есть request and Response, просто замените эту часть на вашу StreamReader reader = new StreamReader(tcpClient.GetStream());, имеет ли это смысл ..?   -  person MethodMan    schedule 08.10.2015


Ответы (1)


Не могли бы вы просто использовать StreamWriter для потоковой передачи содержимого в файл по мере его поступления?

StreamReader reader = new StreamReader(tcpClient.GetStream());

// first message is file size
string cmdFileSize = reader.ReadLine();

// first message is filename
string cmdFileName = reader.ReadLine();

int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;

using (FileStream writer = File.OpenWrite("outfile.dat"))
{
    while (received < length)
    {
        remaining = length - received;
        if (remaining < size)
        {
            size = remaining;
        }

        read = tcpClient.GetStream().Read(buffer, 0, size);
        received += read;
        writer.Write(buffer, 0, size);

        if (read < size)
        {
            break;
        }
    }
}

Кроме того, я думаю, что у вас есть ошибка в вашем коде. Я предполагаю, что вы используете System.Net.Sockets.TcpClient, который возвращает объект NetworkStream при вызове GetStream(). В этом случае второй аргумент метода Read, вероятно, всегда должен быть равен 0. Этот аргумент указывает, где в переменной buffer начинать запись данных, считанных из сети. Если вы не используете 0, вы, вероятно, получите исключение массива за пределами границ. Ознакомьтесь с документами для метода Stream.Read.

person d512    schedule 08.10.2015
comment
Это, вероятно, находится за пределами моего понимания (это означает, что мой мозг начинает дымиться), но вы говорите, что смещение getstream всегда должно быть равно нулю, потому что я всегда буду хотеть все из гетстрима? Это имеет смысл для меня. Или я ошибаюсь? - person Lewis Cianci; 08.10.2015
comment
По сути, я просто говорю, что его следует читать = tcpClient.GetStream().Read(buffer, 0, size); - person d512; 08.10.2015
comment
Могу ли я переключить File.CreateText на новый StreamWriter (файл назначения)? Я не всегда буду писать текст :) Вероятно, большую часть времени я буду писать двоичный код. - person Lewis Cianci; 08.10.2015
comment
Вы можете использовать FileStream, который работает так же, как NetworkStream. Я обновил ответ, чтобы отразить это (и исправить ошибку, о которой я упоминал). - person d512; 08.10.2015
comment
Спасибо. На практике этот код работает очень медленно... по петле он передает около мегабайта каждую минуту. никак не могу понять :( - person Lewis Cianci; 12.10.2015
comment
Ваше сетевое соединение медленное? Вы можете попробовать заменить сетевой поток потоком из файла на вашем локальном компьютере. Если с файлом работает намного быстрее, то, вероятно, дело в сетевом подключении. - person d512; 13.10.2015
comment
Ну, это по петле, разве это не должно быть очень-очень быстро? - person Lewis Cianci; 13.10.2015
comment
Я полагаю, что да, но это может быть то, что генерирует поток сетевых данных, который работает медленно. Замена его файлом, как я предложил выше, может сказать вам об этом. Кроме этого, я не могу сказать, не имея вашего кода. - person d512; 17.10.2015
comment
Ага. По сути, все, что я пытаюсь сделать, это перебрать серию файлов и отправить их с клиента на сервер. И клиент, и сервер завернуты в один и тот же exe, но сервер работает в другом потоке. Мне бы хотелось пример или что-то еще о том, как кто-то еще заставил это работать, я уверен, что это достаточно распространенная проблема. - person Lewis Cianci; 17.10.2015