Тема: JScript: Альтернативные чтение и запись файлов
Приветствую. Думаю, что для вас не секрет, что чтение файлов посредством FileSystemObject и ADODB.Stream довольно тормозное. Хорошей и скоростной альтернативой может послужить SAPI.spFileStream.
В общем, я написал обертку, которая позволяет работать с файлами как с бинарными данными, так и с текстовыми. Она позволяет работать с файлами огромного размера на высокой скорости. Данная технология не грузит файлы целиком в память, а работает только с нужными фрагментами. В настоящий момент осуществляется поддержка текстовой кодировки UTF-8.
Функции:
FileOpen (FilePath, Mode) - Открытие файла. FilePath - это путь к файлу. Mode - режим открытия, принимает следующие значения: 0 (по умолчанию) - режим чтения, 1 - режим записи (каретка находится в конце файла), 2 - режим перезаписи, 8 - создание структуры папок, если ее не существует. Возвращает так называемый FileHandle.
FileRead (FileHandle, count, result) - Читает файл. FileHandle - это либо путь к файлу, либо то, что возвращает FileOpen. сount (по умолчанию - 0) - сколько байт читать. Если параметр равен нулю или опущен, то считывается весь файл. result - объект, в котором будут записаны свойства buffer (результат чтения) и count (сколько байт прочитано). Функция возвращает то, что было прочитано (то же самое, что result.buffer).
FileReadLine(FileHandle) - Читает строку в файле.
FileWrite(FileHandle, data) - Пишет в файл. FileHandle - это либо путь к файлу, либо то, что возвращает FileOpen. data - данные.
FileWriteLine(FileHandle, data) - без комментариев.
FileGetPos (FileHandle) - текущая позиция в файле.
FileSetPos(FileHandle, offset, origin). Задает позицию в файле. offset - смещение в байтах. origin - относительно чего осуществится смещение. Принимает следующие значения: 0 (по умолчанию) - начало файла, 1 - текущая позиция, 2 - конец файла.
Пример:
var Stream = FileOpen(GetScriptFullPath()+".123.txt", 2);
MsgBox(FileGetPos(Stream));
FileWriteLine(Stream, "Hello!");
FileWrite(Stream, "Привет!");
FileSetPos(Stream, 0, 0);
MsgBox(FileRead(Stream));
FileSetPos(Stream, 0, 0);
MsgBox(FileReadLine(Stream));
MsgBox(FileReadLine(Stream));
FileSetPos(Stream, 0, 0);
FileWrite(Stream, ArrayToBinary([65,65,65,65,65,65,65,65,65,65,65,65,65,65])); // пишем побайтово
FileSetPos(Stream, 0, 0);
MsgBox(FileReadLine(Stream, 10));
Exit();
А теперь весь код 8-)
var GlobalObject = this;
var FSO = fso = new ActiveXObject("Scripting.FileSystemObject");
var WshShell = new ActiveXObject("WScript.Shell");
if (GlobalObject.WScript && FileExists("%WinDir%\\SysWow64\\wscript.exe") && !/wow64/i.test(WScript.FullName + "")) {
WshShell.Run("%WinDir%\\SysWow64\\wscript.exe \"" + WScript.FullName + "\"", 1, 0);
WScript.Quit();
}
var vbs = "\r\n\
Function [_MidB](v, s, l):[_MidB]=MidB(v, s+1, l):End Function\r\n\
Function [_Asc](v):[_Asc]=Asc(v):End Function\r\n\
Function [_Chr](v):[_Chr]=Chr(v):End Function\r\n\
Function [_LenB](v):[_LenB]=LenB(v):End Function\r\n\
Function [_VarType](v):[_VarType]=VarType(v):End Function\r\n\
Function [_TypeName](v):[_TypeName]=TypeName(v):End Function\r\n\
Function [_ChrB](v):[_ChrB]=ChrB(v):End Function\r\n\
Function [_AscB](v):[_AscB]=AscB(v):End Function\r\n\
Function [_LeftB](v, l):[_LeftB]=LeftB(v, l):End Function\r\n\
Function [_RightB](v, l):[_RightB]=RightB(v, l):End Function\r\n\
Function [_InstrB](start, stringtosearch, stringtofind, comparemode):[_InstrB]=InstrB(start, stringtosearch, stringtofind, comparemode):End Function\r\n\
\r\n\
Sub ConvertBinaryToJSArray(arrByteArray, js_arr)\r\n\
Dim i\r\n\
For i = 1 To LenB(arrByteArray)\r\n\
js_arr.push(AscB(MidB(arrByteArray, i, 1)))\r\n\
Next\r\n\
End Sub\r\n\
\r\n\
Function MultiByteToBinary(MultiByte)\r\n\
\' 2000 Antonin Foller, http://www.motobit.com\r\n\
\' MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)\r\n\
\' Using recordset\r\n\
Dim RS, LMultiByte, Binary\r\n\
Const adLongVarBinary = 205\r\n\
Set RS = CreateObject(\"ADODB.Recordset\")\r\n\
LMultiByte = LenB(MultiByte)\r\n\
If LMultiByte>0 Then\r\n\
RS.Fields.Append \"mBinary\", adLongVarBinary, LMultiByte\r\n\
RS.Open\r\n\
RS.AddNew\r\n\
RS(\"mBinary\").AppendChunk MultiByte & ChrB(0)\r\n\
RS.Update\r\n\
Binary = RS(\"mBinary\").GetChunk(LMultiByte)\r\n\
End If\r\n\
MultiByteToBinary = Binary\r\n\
End Function\r\n\
\r\n\
Function RSBinaryToString(xBinary)\r\n\
\'1999 Antonin Foller, Motobit Software\r\n\
\'This function converts binary data (VT_UI1 | VT_ARRAY or MultiByte string)\r\n\
\'to string (BSTR) using ADO recordset\r\n\
\'The fastest way - requires ADODB.Recordset\r\n\
\'Use this function instead of MBBinaryToString if you have ADODB.Recordset installed\r\n\
\'to eliminate problem with PureASP performance\r\n\
\r\n\
Dim Binary\r\n\
\'MultiByte data must be converted to VT_UI1 | VT_ARRAY first.\r\n\
if vartype(xBinary) = 8 then Binary = MultiByteToBinary(xBinary) else Binary = xBinary\r\n\
\r\n\
Dim RS, LBinary\r\n\
Const adLongVarChar = 201\r\n\
Set RS = CreateObject(\"ADODB.Recordset\")\r\n\
LBinary = LenB(Binary)\r\n\
\r\n\
if LBinary>0 then\r\n\
RS.Fields.Append \"mBinary\", adLongVarChar, LBinary\r\n\
RS.Open\r\n\
RS.AddNew\r\n\
RS(\"mBinary\").AppendChunk Binary\r\n\
RS.Update\r\n\
RSBinaryToString = RS(\"mBinary\")\r\n\
Else\r\n\
RSBinaryToString = \"\"\r\n\
End If\r\n\
End Function\r\n\
\r\n\
Sub SAPIFileRead(o, count, js_obj)\r\n\
Dim s, buffer\r\n\
s = o.Read(buffer, count)\r\n\
js_obj.count = s\r\n\
js_obj.buffer = buffer\r\n\
End Sub\r\n\
";
var VBSEngine = new ActiveXObject('ScriptControl');
VBSEngine.Language = 'VBScript';
VBSEngine.AddCode(vbs);
function VarType(s)
{
return VBSEngine.CodeObject._VarType(s);
}
function TypeName(s)
{
return VBSEngine.CodeObject._TypeName(s);
}
WshShell.CurrentDirectory = GetScriptDir();
function GetScriptDir() {
return GetScriptFullPath().replace(/[^\\]+$/g, "");
}
//MsgBox(GetScriptDir());
//Exit();
//@ScriptFullPath Equivalent to @ScriptDir & "\" & @ScriptName
function GetScriptFullPath() {
if (GlobalObject.location && GlobalObject.location.href) return location.href.replace(/^.+\/\/\//, "").replace(/\//g, "\\");
if (GlobalObject.WScript) return WScript.ScriptFullName;
return "";
}
//MsgBox(GetScriptFullPath());
//Exit();
function MsgBox(strText, strTitle, nType) {
return WshShell.Popup(strText, 0, strTitle, nType);
}
function Exit() {
if (GlobalObject.WScript) WScript.Quit();
if (GlobalObject.window) window.close();
}
//BinaryMid Extracts a number of bytes from a binary variant. Start - 0
function BinaryMid(s, l, c) {
return VBSEngine.CodeObject._MidB(s, l, c);
}
function BinaryLen(s) {
return VBSEngine.CodeObject._LenB(s);
}
// -1 = not found
function BinaryInBinary(stringtosearch, stringtofind, start, comparemode) {
if (!start) start = 1;
else start++;
return VBSEngine.CodeObject._InstrB(start, stringtosearch, stringtofind, comparemode) - 1;
}
//MsgBox(BinaryInBinary(Binary("123123123"), Binary("123")));
//array of integers (bytes) to ByteArray
function ArrayToBinary(ar) {
var ms = new ActiveXObject("SAPI.spMemoryStream");
for (var i=0, l=ar.length; i<l;i++)
{
ms.Write(ar[i]);
ms.Seek(i+1);
}
s = ms.GetData();
var l = BinaryLen(s);
s = BinaryMid(s, 0, l-3)
return MultiByteToBinary(s);
}
function BinaryToArray(binary) {
var ar = [];
VBSEngine.CodeObject.ConvertBinaryToJSArray(binary, ar);
return ar;
}
function MultiByteToBinary(x)
{
return VBSEngine.CodeObject.MultiByteToBinary(x);
}
//FileExists Checks if a file or directory exists.
function FileExists(Path) {
Path = WshShell.ExpandEnvironmentStrings(Path);
return FSO.FolderExists(Path) || FSO.FileExists(Path);
}
//FileDelete Delete one or more files. (принудительное удаление. принимает как массивы файлов, так и просто путь) поддерживает удаление по маске.
function FileDelete(Path) {
if (/Array/i.test(Path.constructor + "")) {
for (var i = 0, l = Path.length; i < l; i++)
FileDelete(Path[i]);
return true;
}
Path = WshShell.ExpandEnvironmentStrings(Path);
try {
FSO.DeleteFile(Path, true);
return 1;
} catch (e) {
return 0
}
}
function FileOpen(FilePath, Mode)
{
var StreamMode = 0;
if (!FilePath) return false;
if (!Mode) Mode = 0;
if (Mode & 0) {StreamMode = 0;}
if (Mode & 1) {StreamMode = 1;}//Write mode (append to end of file)
if (Mode & 2) {FileDelete(FilePath); FSO.CreateTextFile(FilePath).Close(); StreamMode = 1;}//$FO_OVERWRITE (2) = Write mode (erase previous contents)
if (Mode & 8) DirCreate(FileGetDirectory(FilePath)); //$FO_CREATEPATH (8) = Create directory structure if it doesn't exist (See Remarks).
var Stream = new ActiveXObject("SAPI.spFileStream")
Stream.Open(FilePath, StreamMode);
if (Mode & 1) FileSetPos(Stream, 0, 2); //$FO_APPEND (1) = Write mode (append to end of file)
return Stream;
}
//FileRead Read in a number of characters from a previously opened text file.
function FileRead(FileHandle, count, result)
{
if (!result) result = {};
if (typeof FileHandle == "string")
{
if (!count) count = FileGetSize(FileHandle);
FileHandle = FileOpen(FileHandle, 0);
}
result.count = 0;
result.buffer = "";
if (!count) count = 1024;
VBSEngine.CodeObject.SAPIFileRead(FileHandle, count, result);
// MsgBox(result.buffer);
// MsgBox(result.count);
return result.buffer;
}
//FileSetPos Sets the current file position.
/*
Origin
Must be one of the following:
$FILE_BEGIN (0) = Beginning of the file.
$FILE_CURRENT (1) = Current position.
$FILE_END (2) = End of the file.
Constants are defined in FileConstants.au3
*/
function FileSetPos(FileHandle, offset, origin)
{
if (!origin) origin = 0;
return FileHandle.Seek(offset, origin);
}
//FileGetPos Retrieves the current file position.
function FileGetPos(FileHandle)
{
return FileSetPos(FileHandle, 0, 1);
}
//FileWrite Append a text/data to the end of a previously opened file.
function FileWrite(FileHandle, data)
{
if (typeof FileHandle == "string")
{
FileHandle = FileOpen(FileHandle, 1);
}
if (typeof data == "string")
{
data = MultiByteToBinary(data);
}
return FileHandle.Write(data);
}
//FileWriteLine Append a line of text to the end of a previously opened text file.
function FileWriteLine(FileHandle, data)
{
return FileWrite(FileHandle, data + "\r\n");
}
//FileReadLine Read in a line of text from a previously opened text file.
function FileReadLine(FileHandle)
{
if (typeof FileHandle == "string")
{
FileHandle = FileOpen(FileHandle, 0);
}
var result = {count:0, buffer:""},
startPos = FileGetPos(FileHandle),
pos = -1, i=0, step = 1024, len=2,
buffer, CrLf = ArrayToBinary([13,0,10,0]),
Cr = ArrayToBinary([13,0]);
while (true){
FileRead(FileHandle, step, result);
pos = BinaryInBinary(result.buffer, CrLf);
if (pos!=-1) {len=4; break};
pos = BinaryInBinary(result.buffer, Cr);
if (pos!=-1) {len=2; break};
if (result.count>4) {FileSetPos(FileHandle, -4, 1); i+=step-4;} else
i+=step;
if (result.count!=step) break;
}
var result = "";
if (pos==0) {FileSetPos(FileHandle, startPos+len, 0); return ""};
FileSetPos(FileHandle, startPos, 0);
result = FileRead(FileHandle, i+pos);
FileSetPos(FileHandle, len, 1);
return result;
}
var Stream = FileOpen(GetScriptFullPath()+".123.txt", 2);
MsgBox(FileGetPos(Stream));
FileWriteLine(Stream, "Hello!");
FileWrite(Stream, "Привет!");
FileSetPos(Stream, 0, 0);
MsgBox(FileRead(Stream));
FileSetPos(Stream, 0, 0);
MsgBox(FileReadLine(Stream));
MsgBox(FileReadLine(Stream));
FileSetPos(Stream, 0, 0);
FileWrite(Stream, ArrayToBinary([65,65,65,65,65,65,65,65,65,65,65,65,65,65]));
FileSetPos(Stream, 0, 0);
MsgBox(FileReadLine(Stream, 10));
Exit();