Что может заставить FileStream читать 0 байтов из явно заблокированного файла? - PullRequest
1 голос
/ 16 августа 2011

У меня есть метод 'pack files', написанный на J #, который берет кучу файлов и записывает их все в поток вместе с некоторыми достаточными метаданными, чтобы их можно было реконструировать как отдельные файлы с помощью связанного метода 'unpack'.В конце этого вопроса я предоставил черновую версию, которая дает хорошее представление о том, что делает базовый J #.Я получил это, запустив рефлектор .NET поверх кода J # для генерации эквивалентных библиотек J #.

Теперь приведенный ниже код отлично работает в процессе разработки, но периодически испытывает ошибки в работе.Исключения, помеченные в комментариях ниже как «Ошибка 1» и «Ошибка 2», были замечены в дикой природе.В случае, когда возникает «ОШИБКА 2», всегда записывается 0 байтов.Нет явной картины, когда эти ошибки происходят.Размеры используемых файлов обычно не превышают 100 КБ.

Файлы, которые передаются в метод «pack», были созданы совсем недавно, как и в миллисекундах назад, время настенных часов.Выходной поток указывает на файл, который был недавно создан без совместного использования.

Таким образом, чтобы подвести итог, иногда я получаю длину файла 0, возвращенную для файла, который, как я знаю, существует ... потому что я только что создал его.Из-за участия J # я не могу получить фактическое исключение.(Конечно, если бы я отлаживал, я мог бы использовать исключение первого шанса, но, как уже упоминалось, этого никогда не происходит в среде разработки).В других случаях я не могу прочитать какие-либо байты из файла, даже если он был успешно открыт.В процессе копирования есть исключение, я могу только предположить, что «Read» вернул -1.

Что здесь может происходить?Есть идеи?Я подозреваю, что в Prod работает проверенный вирус, но не dev, и, возможно, он каким-то образом замешан.Но что может сделать средство проверки на вирусы, когда у меня есть файл, открытый и заблокированный (как в методе WriteToStream), который может остановить чтение без ошибки?Я написал небольшое тестовое приложение, которое может блокировать произвольные файлы ... но блокировка файла из другого процесса, похоже, не останавливает работу FileInfo.Length, и как только поток файлов открывается, мое тестовое приложение больше не может блокироватьфайл, как и следовало ожидать.

Я в тупике, я.

РЕДАКТИРОВАТЬ:

Хорошо - здесь вместо этого код J #.Повторно пометил вопрос.

РЕДАКТИРОВАТЬ 2:

Я должен также упомянуть, что проверка для длины 0 была добавлена ​​позже для устранения неполадок.До этого это всегда просто сбой после сравнения «длина» с «написано».Поэтому, когда «длина» не равна «записано», иногда «длина» равна 0, а иногда «записано» равно 0. Я уверен, что проблема НЕ является ошибкой в ​​моем коде, а вызвана чем-то внешним.Цель этого вопроса - выяснить, что другой процесс (например, средство проверки на вирусы) может сделать с этими файлами, чтобы мой код не работал так, как я описываю.

public static void packContentsToStream(Serializable serializable, Stream stream)
{
    try
    {
        OutputStream output = new StreamWrapperOutputStream(stream);

        FileRecordPair[] recordPairs = SerializationUtil.getRecords(serializable);
        FileRecord[] records = new FileRecord[recordPairs.length];
        File[] files = new Files[recordPairs.length];

        for (int i = 0; i < recordPairs.length; i++)
        {
            FileRecordPair pair = recordPairs[i];
            records[i] = pair.getRecord();
            files[i] = pair.getFile();
        }

        SerializationUtil.writeToStream(serializable, output, false); // False keeps stream open
        SerializationUtil.writeToStream(records, output, false);

        for (int i = 0; i < files.length; i++)
        {
            File file = files[i];
            long written = writeToStream(file, output);
            if (written != records[i].getFileLength())
            {
                throw new SystemException("Invalid record. The number of bytes written [" + written + "] did not match the recorded file length [" + records[i].getFileLength() + "]."); // ERROR 2
            }
        }
     }
     catch (Exception e)
     {
        throw new SystemException("Could not write FileRecords", e);
     }
}


public static long writeToStream(HapiFile file, OutputStream stream)
{
    long written = 0;
    if (file.exists())
    {
        FileInputStream fis = null;
        try
        {
            fis = new FileInputStream(file);
            written = copy(fis, stream);
        }
        catch (Exception e)
        {
            throw new SystemException("Could not write file to stream", e);
        }
        finally
        {
            if (fis != null)
            {
                try
                {
                    fis.close();
                }
                catch (IOException ioe)
                {
                    // For now - throw an exception to see if this might be causing the packing error
                    throw new SystemException("Error closing file", ioe);
                }
            }
        }
    }

    return written;
}

public static int copy(InputStream is, OutputStream stream) throws IOException
{
    int total = 0;
    int read = 0;
    byte[] buffer = new byte[BUFFER_SIZE];

    while (read > -1)
    {
        read = is.read(buffer);
        if (read > 0)
        {
            stream.write(buffer, 0, read);
            total += read;
        }
    }

    return total;
}

// Relevant part of 'SerializationUtil.getRecords'

private static FileRecord GetFor(File file, String recordName, int index, String pathToInstance) 
{
    String fileName = file.getName();
    int length = (int) file.length(); // Safe as long as file is under 2GB

    if (length == 0) 
    {
        throw new SystemException("Could not obtain file length for '" + file.getPath() + "'"); // ERROR 1
    }

    if (index > -1 && recordName != null && recordName.length() > 0) 
    {
        recordName = recordName + "." + index;
    }

    return new FileRecord(fileName, length, recordName, pathToInstance);
}

// File.length() implementation - obtained using .NET Reflector
public virtual long length()
{
    long length = 0L;
    if (this.__fileInfo != null)
    {
        SecurityManager manager = System.getSecurityManager();
        if (manager != null)
        {
            manager.checkRead(this.__mCanonicalPath);
        }
        try
        {
            this.__fileInfo.Refresh();
            if (!this.exists() || !(this.__fileInfo is FileInfo))
            {
                return 0L;
            }
            length = ((FileInfo) this.__fileInfo).Length;
        }
        catch (FileNotFoundException)
        {
        }
        catch (IOException)
        {
        }
    }
    return length;
}

Ответы [ 3 ]

0 голосов
/ 18 августа 2011

Не берите в голову ... Один из объектов в коде C #, который вызывал код J #, имел финализатор, который удалил файл, на который опирался код J #.Код J # был в порядке.Проверка на вирусы не была виновата.У нас просто был диверсант в строю.Сборщик мусора входил и собирал объект, который все еще казался находящимся в области видимости.

0 голосов
/ 10 апреля 2019

используйте функцию обновления для обновления информации о вашем файле

0 голосов
/ 16 августа 2011

Метод WriteToStream. Пожалуйста, закройте файл первым. Всегда используйте блок finally там.

...