Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527

Дублирование байт при загрузке (FTP)

02.12.2015, 05:32. Показов 1588. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую всех. Появилась странная проблема, причин возникновения я в упор не вижу. Суть:
Я загружаю файл по FTP-протоколу следующими функциями:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const int bufferSize = 1024;
 
/// <summary>
/// Создание запроса к серверу
/// </summary>
/// <param name="uri">Путь к папке на сервере, куда будет происходить загрузка</param>
/// <param name="method">Метод запроса</param>
/// <returns></returns>
static private FtpWebRequest createRequest(string uri, string method)
{
    FtpWebRequest reqFTP = (FtpWebRequest)WebRequest.Create(new Uri(uri));
    reqFTP.Credentials = new NetworkCredential(Properties.Settings.Default.serverLogin, Properties.Settings.Default.serverPass);
    reqFTP.KeepAlive = true;
    reqFTP.Method = method;
    reqFTP.UseBinary = true;
    reqFTP.EnableSsl = false;
 
    return reqFTP;
}
 
/// <summary>
/// Загрузка файла с FTP - сервера
/// </summary>
/// <param name="uri">Путь на Ftp</param>
/// <param name="path">Путь, для загрузки файла</param>
private void downloadFile(string uri, string path)
{
    var request = createRequest(uri, WebRequestMethods.Ftp.DownloadFile);
    byte[] buffer = new byte[bufferSize];
    int readCount;
 
 
    try
    {
        using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
        {
            using (var response = (FtpWebResponse)request.GetResponse())
            {
                using (var stream = response.GetResponseStream())
                {
                    readCount = stream.Read(buffer, 0, bufferSize);
 
                    while (readCount > 0)
                    {
                        fs.Write(buffer, 0, bufferSize);
                        readCount = stream.Read(buffer, 0, bufferSize);
                    }
                }
            }
 
            fs.Flush();
        }
    }
    catch {  }
}
Так вот, данный код периодически выгружает файл по нормальному, а периодами - ДУБЛИРУЕТ некоторые байты... точнее не совсем так, судя по всему, после загрузки байт функцией Read, указатель не всегда перемещается вперёд, и считывает те же самые данные несколько раз подряд О_о... При этом, я проверял, даже если считывать по одному байту, то дублируются всё те же объёмы байт. Пример дублирования:

Кликните здесь для просмотра всего текста

Оригинал:
XML
1
2
3
4
5
6
7
8
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
  <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001" />
 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
   <X509Data>
     <X509Certificate>.....</X509Certificate>
   </X509Data>
 </KeyInfo>
 <CipherData>
Что загрузилось:
XML
1
2
3
4
5
6
7
8
9
10
11
12
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>...{Тут строка обрезана, это не я вырезал лишнего}thms:transport-gost2001" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>....</X509Certificate>
        </X509Data>
      </KeyInfo>
      <CipherData>


Добавлено через 7 минут
Хммм... Возможно-ли, что поток просто не успевает скачаться с сервера, потому и дубли? Но объём там всего-лишь 20-30 Кб... И как этого тогда избежать? Да и код шаблонный, не должен такого допускать ,по идее...

Добавлено через 15 минут
О_О... В душе не представляю в чём была проблема, и буду искренне благодарен человеку, который мне это разъяснит, но помогло вот такое изменение кода:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// <summary>
/// Загрузка файла с FTP - сервера
/// </summary>
/// <param name="uri">Путь на Ftp</param>
/// <param name="path">Путь, для загрузки файла</param>
private void downloadFile(string uri, string path)
{
    var request = createRequest(uri, WebRequestMethods.Ftp.DownloadFile);
    byte[] buffer = new byte[bufferSize];
    long readCount = 0;
    long len = getFileSize(uri);
 
    try
    {
        using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
        {
            using (var response = (FtpWebResponse)request.GetResponse())
            {
                using (var stream = response.GetResponseStream())
                {
                    using (BinaryReader br = new BinaryReader(stream))
                    {
                        while (readCount <= len)
                        {
                            buffer = br.ReadBytes(bufferSize);
                            fs.Write(buffer, 0, buffer.Length);
                            readCount += bufferSize;
                        }
                    }
                }
            }
            fs.Flush();
        }
    }
    catch { }
}
Как и почему - не представляю. Сам сделал так просто чтобы попробовать, т.к. до этого перепробовал ещё десяток вариантов решения... При этом пока что грузит всё корректно.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
02.12.2015, 05:32
Ответы с готовыми решениями:

Ошибка (503) при загрузке с Ftp файлов
Здравствуйте, есть задача загрузить все файлы, находящиеся в определённой папке на ftp. Получаю список файлов на сервере в...

Отрезается буква "Я" при загрузке файлов на FTP
Поднял на своей машине (Win 7 Pro + IIS из коробки) FTP. Создал специально для него группу и учётку. Осуществляю от имени созданной...

Почему при загрузке файла с сервера появляются нулевые байты через каждый байт ?
Вот код. &lt;%@ Language=VBScript %&gt; &lt;% Dim sRTF Response.Addheader 'Content-Disposition', 'attachment; filename=xxx.rtf' ...

10
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
02.12.2015, 06:32
В первоначальном коде
C#
1
2
3
4
5
while (readCount > 0)
{
       fs.Write(buffer, 0, bufferSize);
       readCount = stream.Read(buffer, 0, bufferSize);
}
вы сначала записываете в файл, а потом загружаете с фтп, это нормально?

Помоему должно быть так
C#
1
2
3
4
5
6
do
{
       readCount = stream.Read(buffer, 0, bufferSize);
       fs.Write(buffer, 0, readCount);
}
while (readCount > 0);
0
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527
02.12.2015, 06:42  [ТС]
Someone007, между прочим, там сначала считывание идёт, а потом цикл:
C#
1
2
3
4
5
 readCount = stream.Read(buffer, 0, bufferSize);
 
                            while (readCount > 0)
                            {
                                fs.Write(buffer, 0, bufferSize);
Кроме того, этот вариант остался таким после десятка попыток понять причину ошибки. Изначально он и был с do-while. И перепробовал я десяток вариантов вывода, вплоть до считывания по одному байта в память, и последующему сохранению. Результат был одинаковым.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
02.12.2015, 08:29
Считывание то идет, а вот запись некорректная. Вы записываете весь буфер, а не число прочитанных байт...
C#
1
fs.Write(buffer, 0, bufferSize);
vs
C#
1
fs.Write(buffer, 0, readCount);
поэтому на выходе у вас мусор получается.
0
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527
02.12.2015, 11:51  [ТС]
Someone007, ок, но почему тогда ошибка продолжала иметь место, когда я читал по одному байту, через readByte, и записывал аналогично? Кроме того, при в вашем варианте записанное дублировалось бы много раз, а это не так...
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
02.12.2015, 17:57
Цитата Сообщение от Захарка Посмотреть сообщение
почему тогда ошибка продолжала иметь место, когда я читал по одному байту, через readByte, и записывал аналогично
Без понятия что вы там написали, наверняка какую нибудь хрень.

Цитата Сообщение от Захарка Посмотреть сообщение
Кроме того, при в вашем варианте записанное дублировалось бы много раз, а это не так...
С чего бы вдруг оно дублировалось?
0
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527
02.12.2015, 18:09  [ТС]
Someone007, Хрень? Огромное спасибо за столь лестную оценку. Вот код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        /// <summary>
        /// Загрузка файла с FTP - сервера
        /// </summary>
        /// <param name="uri">Путь на Ftp</param>
        /// <param name="path">Путь, для загрузки файла</param>
        private void downloadFile(string uri, string path)
        {
            var request = createRequest(uri, WebRequestMethods.Ftp.DownloadFile);
            byte[] buffer = new byte[bufferSize];
            long readCount;
            long len = getFileSize(uri);
 
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
                {
                    using (var response = (FtpWebResponse)request.GetResponse())
                    {
                        using (var stream = response.GetResponseStream())
                        {
                            readCount = stream.ReadByte();
 
                            while(readCount != -1)
                            {
                                fs.WriteByte((byte)readCount);
                                readCount = stream.ReadByte();
                            }                       
                        }
                    }
                    fs.Flush();
                }
            }
            catch { }
        }
Считывание идёт по одному байту, однако дублирование всё равно происходит.

Добавлено через 7 минут
P.S. Да, с размером записи я слегка протупил, НО! Ничего, что объём считывания фиксированный? При таком варианте он ДОЛЖЕН был КАЖДЫЙ раз считывать из потока 1024 байта, и их же записывать, кроме самого последнего, который мог быть меньше. При таком раскладе, дублирование могло иметь место быть ТОЛЬКО в КОНЦЕ файла, оно же встречалось сразу в нескольких местах. Более того, я добавлял очистку массива, перед каждой итерацией. Если бы считывалось некорректное число байтов, то в файл бы писались нули на место остатка, чего не наблюдалось.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
02.12.2015, 18:59
Цитата Сообщение от Захарка Посмотреть сообщение
Считывание идёт по одному байту, однако дублирование всё равно происходит.
Очень странно, на первый взгляд код должен работать корректно, но он очень неэффективный. Разве что проблема в FileMode.OpenOrCreate...

C#
1
FileMode.OpenOrCreate
А что если новый скачанный файл имеет меньший размер? У вас в конце останется мусор.

Цитата Сообщение от Захарка Посмотреть сообщение
При таком варианте он ДОЛЖЕН был КАЖДЫЙ раз считывать из потока 1024 байта, и их же записывать, кроме самого последнего, который мог быть меньше.
Бред. Никто никому ничего не должен, для этого возвращается конкретное количество прочитанных байт...

Цитата Сообщение от Захарка Посмотреть сообщение
При таком раскладе, дублирование могло иметь место быть ТОЛЬКО в КОНЦЕ файла, оно же встречалось сразу в нескольких местах.
Тоже бред. Как раз из-за того, что вы записывали не прочитанное число байт, а весь буфер, у вас и происходило то, что вы описываете.

Цитата Сообщение от Захарка Посмотреть сообщение
Более того, я добавлял очистку массива, перед каждой итерацией. Если бы считывалось некорректное число байтов, то в файл бы писались нули на место остатка, чего не наблюдалось.
Если вы действительно это делали, то очень странно что нули не записывались.

К тому же
Цитата Сообщение от Захарка Посмотреть сообщение
то в файл бы писались нули на место остатка,
они бы писались на каждой итерации, а не на место остатка...
1
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527
02.12.2015, 19:52  [ТС]
Someone007, да я уже понял, что скорее всего причина в этом... Ответ писал уже скорее из чувства противоречия... Код со считыванием по байту писал чисто посмотреть, авось получится. Ааа... блин, я понял в чём лажанулся... Умудрился, ещё фиг знает когда, прочитать, что третий аргумент - не максимальное количество байт, которое нужно считать с потока, а количество байт, которое необходимо считать с потока, и с тех пор был свято в этом уверен...
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
02.12.2015, 21:25
Лучший ответ Сообщение было отмечено Psilon как решение

Решение

Захарка, мой рабочий код, который используется у нас в нескольких суровых проектах. Работоспособность гарантируется Со стороны может показаться, что есть лишние копирования, но на самом деле все вымучено всякими интересными сайд-эффектами.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    public class FtpClient : IDataClient
    {
        public static bool IsDirectory(string directory)
        {
            if (directory == null)
            {
                throw new ArgumentNullException(); 
            }
            return string.IsNullOrEmpty(Path.GetExtension(directory));
        }
        #region properties
 
        public string Login { private get; set; }
        public string Password { private get; set; }
        public IWebProxy Proxy { private get; set; }
 
        #endregion
 
        public FtpClient() { }
 
        public void Dispose()
        {
 
        }
 
        public string GetRequest(Uri query)
        {
            bool isDirectory = IsDirectory(query.OriginalString);
            return isDirectory ? ListDirectory(query) : DownloadFile(query);
        }
 
        #region private Methods
 
        public FtpWebRequest CreateFtpWebRequest(Uri uri, String method)
        {
            var result = (FtpWebRequest)WebRequest.Create(uri.AbsoluteUri.ToUrlWithFtpScheme());
            result.Method = method;
            result.Proxy = Proxy;
            result.Timeout = 60 * 1000;
 
            result.KeepAlive = true;
            result.ConnectionGroupName = "FCS";
            result.ServicePoint.ConnectionLimit = 32;
 
            if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password))
            {
                result.Credentials = new NetworkCredential(Login, Password);
            }
            return result;
        }
 
        private string ListDirectory(Uri query)
        {
            var request = CreateFtpWebRequest(query, WebRequestMethods.Ftp.ListDirectory);
            using (var response = request.GetResponse())
            using (var reader = new StreamReader(response.GetResponseStream()))
            {
                return reader.ReadToEnd();
            }
        }
 
        private string DownloadZip(Uri query)
        {
            if (!query.AbsoluteUri.EndsWith(".zip"))
                throw new ArgumentException("Expected ZIP archive", "query");
            var request = CreateFtpWebRequest(query, WebRequestMethods.Ftp.DownloadFile);
            using (var response = request.GetResponse())
            using (var stream = response.GetResponseStream())
            using (var bufferStream = new MemoryStream())
            {
                Trace.Assert(stream != null);
                stream.CopyTo(bufferStream); // ZipInputStream плохо работает с сетевыми потоками, поэтому сначала перегоняем в промежуточный MemoryStream
                bufferStream.Seek(0, SeekOrigin.Begin);
                using (var zip = new ZipInputStream(bufferStream))
                {
                    var entry = zip.GetNextEntry();
                    if (entry == null)
                        throw new Exception("Error while unpacking source");
                    using (var sr = new StreamReader(zip, Encoding.UTF8))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
        }
 
        public string DownloadFile(Uri query)
        {
            if (query.AbsoluteUri.EndsWith(".zip"))
                return DownloadZip(query);
            var request = CreateFtpWebRequest(query, WebRequestMethods.Ftp.DownloadFile);
            using (var response = request.GetResponse())
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                return sr.ReadToEnd();
            }
        }
 
        #endregion
    }
Добавлено через 6 минут
В вашем случае, когда нужно скачать в путь:
C#
1
2
3
4
5
6
7
8
9
10
        public void DownloadFile(Uri query, string path)
        {
            var request = CreateFtpWebRequest(query, WebRequestMethods.Ftp.DownloadFile);
            using (var response = request.GetResponse())
            using (var respStream = response.GetResponseStream())
            using (var fs = new FileStream(path, FileMode.Create))
            {
                respStream.CopyTo(fs);
            }
        }
1
135 / 130 / 60
Регистрация: 16.06.2013
Сообщений: 527
03.12.2015, 02:21  [ТС]
Psilon, Спасибо огромное. Буду разбираться. У меня как раз архивы качаются...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.12.2015, 02:21
Помогаю со студенческими работами здесь

Убрать подвисание при загрузке на FTP
Собственно говоря, проблема в том что при выполнении загрузки файла на FTP компьютер просто забаговывается, отлично заметно когда пишешь...

Ошибка при загрузке большого файла на ftp
Пытаюсь сделать FTP-клиент, но при загрузке файла(~300 Mb) возникает ошибка The underlying connection was closed: An unexpected error...

Кодировка при загрузке файла на FTP сервер
Здравствуйте, у меня возникла проблема с правильной загрузкой файла на FTP сервер. Файл загружается, но русские символы показываются в виде...

Ошибка при загрузке файла с FTP-сервера
Привет всем! В моей программе есть функция проверки обновления и закачки его после запроса. Делаю это так: Public Address...

Сбивается форматирование при загрузке через ftp
сегодня случилась такая беда: открываю php файлы на локальном компьютере - всё нормально. как только закидываю по фтп, сбивается весь код в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru