私はアーカイブとして機能する独自のファイル形式を持っています。これは、ファイルがいっぱいのフォルダを取り、それらを圧縮せずに単一のファイルにパックします。ファイルの最初のXバイトはファイルのパス、バイト単位のサイズ、およびその位置(バイトインデックス)です。アーカイブファイルに保存します。残りのバイトは各ファイルの実際のデータ用です。私の独自のファイル形式がアーカイブを解除できないのはなぜですか?
このフォーマットは、いくつかのケースで私がデバッグしようとしていることを除いて、何年も働いています。ファイルが適切に解凍できない場合があります。私の経験では、これは通常、5400 rpmのハードディスクドライブを搭載していると思われるラップトップにあります。しかし、SSDハードドライブ(サーフェスブックなど)で障害が発生することもあります。 「問題のある」マシンで同じファイルを10回展開すると、1回または2回失敗したり、まったく失敗することがあります。
この形式(as3)をアーカイブ解除する言語では、ファイルストリームリーダーにはプロパティ 'readAhead'があります。これは、ドキュメントが示すとおり、「ファイルを非同期に読み取るときに読み取るデータの最小量」です。この価値が私の保管に影響を与えることはありますか?これに対する私の初期値は '8192'でした。私は現在、いくつかの新しいマシンでテストするために8192/4に変更しました。誰もがこれについて考えている? readAheadの値は無関係ですか?
これはあいまいです。私は、この問題をよりよく診断し解決するために、より多くの経験を積んだ人からのフィードバックを得たいと思う特定のソリューションを探しているわけではありません。
ここに問題のクラスがあります。ちょうど私の個人的な意見。これは、コメントの長すぎた
/**
* ...
* @author Phil
*/
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.Endian;
public class Archive extends EventDispatcher
{
public static const UNARCHIVING_COMPLETE:String = "unarchivingComplete";
public static const UNARCHIVING_PROGRESS:String = "unarchivingProgress";
public static const UNARCHIVE_CANCEL:String = "unarchiveCancel";
public static const ENDIAN:String = Endian.LITTLE_ENDIAN;
private var _inputFile:File;
private var _outputFile:File;
private var _inputStream:FileStream;
private var _outputStream:FileStream;
private var _files:Vector.<ArchiveItem>;
private var _readAheadValue:uint = 8192/4;
private var _maxTableSize:uint = 40960 * 30;
private var _tableData:ByteArray;
private var _curArchiveItem:ArchiveItem;
private var _currentArchiveItemBytesWritten:uint;
private var _pointerPosition:uint = 0;
private var _tableSize:uint = 0;
private var _totalSize:uint = 0;
private var _totalFiles:uint = 0;
public function Archive()
{
}
public function readArchive(archive:File, dest:File):void
{
_inputFile = archive;
_outputFile = dest;
createReadStream();
createTableData();
_inputStream.openAsync(_inputFile, FileMode.READ);
}
public function destroy():void
{
killStreams();
_inputFile = null;
_outputFile = null;
}
public function cancel():void
{
killStreams();
}
private function killStreams():void
{
killInStream();
killOutStream();
}
private function killInStream():void
{
if (!_inputStream) return;
_inputStream.removeEventListener(Event.COMPLETE, onFileReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onFileReadProgress);
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.removeEventListener(Event.CLOSE, onInputClosed);
_inputStream.removeEventListener(IOErrorEvent.IO_ERROR, onErrorReadingArchive);
_inputStream.close();
_inputStream = null;
}
private function killOutStream():void
{
if (!_outputStream) return;
_outputStream.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
_outputStream.removeEventListener(Event.CLOSE, onOutPutClosed);
_outputStream.close();
_outputStream = null;
}
private function createTableData():void
{
_files = new Vector.<ArchiveItem>();
_tableData = new ByteArray();
_tableData.endian = ENDIAN;
}
private function createReadStream():void
{
_inputStream = new FileStream();
_inputStream.endian = ENDIAN;
_inputStream.readAhead = _readAheadValue;
_inputStream.addEventListener(Event.CLOSE, onInputClosed);
_inputStream.addEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.addEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.addEventListener(IOErrorEvent.IO_ERROR, onErrorReadingArchive);
}
private function onErrorReadingArchive(e:IOErrorEvent):void
{
dispatchEvent(new Event(Event.CANCEL));
}
private function onArhiveReadComplete(e:Event):void
{
if (_tableData.length < _maxTableSize)
{
onTableReadProgress(null, true);
}
}
private function onTableReadProgress(e:ProgressEvent, force:Boolean = false):void
{
if (_tableData.length < _maxTableSize && force == false)
{
_inputStream.readBytes(_tableData,_tableData.length);
}else {
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
populateTable(_tableData);
}
return;
if (_inputStream.bytesAvailable < _maxTableSize && force == false)
{
return;
}else {
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
var ba:ByteArray = new ByteArray();
ba.endian = ENDIAN;
_inputStream.readBytes(ba);
populateTable(ba );
}
}
private function populateTable(tableData:ByteArray):void
{
var a:ArchiveItem;
var offset:uint = 0;
var size:uint = 0;
var fileName:String;
if (tableData is ByteArray)
{
tableData.position = 0;
}
for (;;)
{
offset = tableData.readUnsignedInt();
size = tableData.readUnsignedInt();
fileName = tableData.readUTF();
if (fileName == "endTable")
{
_tableSize = tableData.position;
_totalFiles = _files.length;
_totalSize = _inputFile.size;
completeTableRead();
break;
}
a = new ArchiveItem();
a.filename = fileName;
a.offset = offset;
a.size = size;
_files.push(a);
}
}
private function completeTableRead():void
{
createFileOutputStream();
_inputStream.readAhead = _readAheadValue;
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.addEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.addEventListener(Event.COMPLETE, onArchiveReadProgress);
writeNextArchiveItemToFile();
}
private function onInputClosed(e:Event):void
{
completeUnarchiving();
}
private function completeUnarchiving():void
{
killStreams();
dispatchEvent(new Event(UNARCHIVING_COMPLETE));
}
private function createFileOutputStream():void
{
_outputStream = new FileStream();
_outputStream.endian = ENDIAN;
_outputStream.addEventListener(Event.CLOSE, onOutPutClosed);
_outputStream.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
}
private function onOutPutClosed(e:Event):void
{
completeUnarchiving();
}
private function onIOError(e:IOErrorEvent):void
{
dispatchEvent(new Event(Event.CANCEL));
}
private function writeNextArchiveItemToFile():void
{
if (_files.length == 0)
{
endWriting();
return;
}
_curArchiveItem = _files.shift();
_currentArchiveItemBytesWritten = 0;
var dest:File = new File();
dest.nativePath = _outputFile.nativePath + File.separator + _curArchiveItem.filename;
_outputStream.open(dest, FileMode.WRITE);
movePointer();
}
private function endWriting():void
{
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.removeEventListener(Event.COMPLETE, onArchiveReadProgress);
_outputStream.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
_outputStream.close();
_inputStream.close();
}
private function onOutputStreamCloseOnCompelte(e:Event):void
{
dispatchEvent(new Event(UNARCHIVING_COMPLETE));
}
private function movePointer():void
{
_inputStream.position = _tableSize + _curArchiveItem.offset;
_pointerPosition = _inputStream.position;
if (_curArchiveItem.size == 0)
{
writeNextArchiveItemToFile();
}
}
private function onArchiveReadProgress(e:Event):void
{
if (_currentArchiveItemBytesWritten >= _curArchiveItem.size)
{
writeNextArchiveItemToFile();
return;
}
writeBytesToDisk();
}
private function writeBytesToDisk():void
{
var bytes:ByteArray = new ByteArray();
var bytesRemaining:uint = _curArchiveItem.size - _currentArchiveItemBytesWritten;
var bytesToWrite:uint = _inputStream.bytesAvailable;
if (bytesToWrite > bytesRemaining)
{
bytesToWrite = bytesRemaining;
}
_inputStream.readBytes(bytes, 0, bytesToWrite);
try {
_outputStream.writeBytes(bytes, 0, bytes.length); //This throws an error on large files.
}catch (e:Error)
{
dispatchEvent(new Event(Event.CANCEL));
return;
}
_currentArchiveItemBytesWritten += bytes.length;
_pointerPosition = _inputStream.position;
dispatchEvent(new Event(UNARCHIVING_PROGRESS));
if (_currentArchiveItemBytesWritten >= _curArchiveItem.size)
{
writeNextArchiveItemToFile();
}
}
}
}
class ArchiveItem
{
public var offset:uint;
public var size:uint;
public var filename:String;
public function ArchiveItem()
{
}
}
誰も本当にあなたを助けることができません。独自のアーカイバ/アンアーカイバを作成し、誰かがそれを修正するのを助けることができるコードを表示せずに作成します。起こらないだろう。 – BotMaster
私は私の決算書に述べたとおりです。私はいくつかの洞察と誰かが持っている可能性のある示唆だけを具体的な助けを求めているわけではありません。それにもかかわらず、私はフィードバックに感謝します。 – Phil
私は理解していますが、たとえ誰かがそれを試みるとしても、暗闇の中で一撃になり、助けになる機会はほとんどありません。 – BotMaster