//file 文件读写 import util.metaProperty namespace fsys; class file{ ctor( path ,mode = "r" ,sharemode = 3/*_FILE_SHARE_READ | _FILE_SHARE_WRITE*/ ,creation = 3/*_OPEN_EXISTING*/ ,flagsAndAttributes ,secAttrib ,template ){ if(type(path)==type.pointer){ this.hfile = path; if(mode===true)..table.gc( this,"close" ); } else{ path = ..io.fullpath(path); if(flagsAndAttributes === null ){ var lastChar = path[#path]; if( lastChar=='/'# || lastChar=='\\'# || ( path[1]!='\\'#/*named pipe*/ && (::Kernel32.GetFileAttributes(path)& 0x10/*_FILE_ATTRIBUTE_DIRECTORY*/) ) ){ flagsAndAttributes = 0x2000000/*_FILE_FLAG_BACKUP_SEMANTICS*/; } } var access = 0; var seekend; if( type(mode) == type.string ){ var f=mode[1]; if( f='r'# ) { creation |= 3/*_OPEN_EXISTING*/ access |= 0x80000000/*_GENERIC_READ*/; } else { creation &= ~3/*_OPEN_EXISTING*/; access |= 0x40000000/*_GENERIC_WRITE*/ if( f='w'# ) { creation |= 2/*_CREATE_ALWAYS*/ } else{ creation |= 4/*_OPEN_ALWAYS*/ seekend = true; } } if(..string.indexAny(mode,"+") ){ access = access | 0x80000000/*_GENERIC_READ*/ | 0x40000000/*_GENERIC_WRITE*/; } if(..string.indexAny(mode,"D") ){ flagsAndAttributes = (flagsAndAttributes:0) | 0x4000000/*_FILE_FLAG_DELETE_ON_CLOSE*/ } } else { access = mode; } if(flagsAndAttributes===null){ flagsAndAttributes = 0x80/*_FILE_ATTRIBUTE_NORMAL*/ if(creation & 2/*_CREATE_ALWAYS*/){ var attr = ::Kernel32.GetFileAttributesW(path); if( attr > 0){ flagsAndAttributes = attr; } } } this.hfile = CreateFile(path,access,sharemode,secAttrib : {} ,creation,flagsAndAttributes ) if( this.hfile == _INVALID_HANDLE_VALUE ) return null,..lasterr() if(seekend) llseek( this.hfile,0 ,0x2/*_SEEK_END*/); this.path = path; ..table.gc(this,"close"); } }; @_metaProperty } var push = ..table.push; namespace file{ _metaProperty = ..util.metaProperty( close = function(){ if(owner.hfile) ..raw.closehandle(owner.hfile) owner.hfile = null; } delete = function(){ if(owner.hfile) ..raw.closehandle(owner.hfile) owner.hfile = null; if(owner.path){ return ..io.remove(owner.path) } } seteof = function(){ if(owner.hfile) return SetEndOfFile(owner.hfile) } seek = function(mode="cur",off=0){ if(owner.hfile){ var ret,off = SetFilePointerEx( owner.hfile,off,0,_seekMode[mode]); if(ret) return off; } } readTo = function(ends){ if( type(ends)!="string" || (!#ends) ) error("参数错误",2); var lends = #ends; var bytes = {} while( var ok,byte; ok,byte,readSize = ReadByte(owner.hfile,0,1,0) ; ok && readSize ) { push(bytes,byte); if( byte == ends[lends]){ var l = #bytes; for(i=lends-1;1;-1){ if( ends[i] != bytes[l-lends + i ] ){ continue 2; } } ..table.pop(bytes,lends); return ..string.pack(bytes); } } }; read = function(len){ if(owner.hfile){ if( type(len)!=type.number){ if( len[["_struct"]] ){ var s = len; var l = ..raw.sizeof(s) ok,s,readSize = ReadStruct(owner.hfile,s,l,0) if(ok && ( l == readSize) )return s; return; } elseif( ( len===null ) or ( len=="%s" ) ){ var bytes = {} var ok,byte = ReadByte(owner.hfile,0,1,0) ; while( byte ? (byte!='\n'#) ){ if( !ok ) { return null,..lasterr(); } if(byte!='\r'#) push(bytes,byte); ok,byte = ReadByte(owner.hfile,0,1,0); } if(#bytes) return ..string.pack(bytes); return byte?"":null; }; error("不支持的参数",2) } elseif(len===0){ var ok,str,readSize = ReadFile( owner.hfile,1,1,0); if(ok && readSize){ SetFilePointerEx( owner.hfile,-readSize,0,1/*_FILE_CURRENT*/) return ""; } return null; } if(len<0) { len = owner.size() - len + 1; } var ok,str,readSize = ReadFile( owner.hfile,len,len,0); if(ok) return readSize ? ..string.left(str,readSize) : null; return null,..lasterr(); } }; readAll = function(){ owner.seek("set"); var len = owner.size(); var ok,str,readSize = ReadFile( owner.hfile,len,len,0); if(ok) return readSize ? ..string.left(str,readSize) : null; }; readLine = lambda() owner.read();//@Deprecated lines = function(){ var f = owner; return function(){ return f.read(); } }; write = function(s,...){ if(owner.hfile){ var st = type(s); if( st != "string" ){ if( st == "number") s = tostring(s); elseif( s[["_struct"]]) s = ..raw.buffer(s); else error("参数类型错误",2); } var ok/*,numBytes*/ = WriteFile( owner.hfile,s,#s,0); if(ok){ if(...===null) return true; return owner.write(...); } return 0; } }; readBuffer = function(buffer,l){ var t = type(buffer); if( t == "buffer" ){ var m = #buffer; if( l=== null ) l = m; elseif( l > m ) l = m; elseif( l < 0 ) return; } else{ if(t!="pointer") error("参数@1必须指定buffer",2); if(!l) error("无效的长度参数@2",2); } var ok,readSize = ReadBuffer( owner.hfile,buffer,l,0); if(ok)return readSize; } writeBuffer = function(buffer,l){ var t = type(buffer); if( t == "buffer" || t == "string" ){ var m = #buffer; if( l=== null ) l = m; elseif( l > m ) l = m; elseif( l < 0 ) return; } else{ if(t!="pointer") error("参数@1必须指定buffer",2); if(!l) error("无效的长度参数@2",2); } var ok,writeSize = WriteFile( owner.hfile,buffer,l,0); if(ok)return writeSize; } flush = function(){ if(owner.hfile){ return FlushFileBuffers( owner.hfile ); } }; setFileTime = function(tm){ if(! owner.hfile) return; var tmkind = ::FILETIME(); if( tmkind._struct != tm[["creation"]][["_struct"]]) error("创建时间不是合法的FILETIME对象",2); if( tmkind._struct != tm[["access"]][["_struct"]]) error("访问时间不是合法的FILETIME对象",2) if( tmkind._struct != tm[["write"]][["_struct"]]) error("修改时间不是合法的FILETIME对象",2) var ok = SetFileTime( owner.hfile,tm.creation,tm.access,tm.write) return ok; }; getFileTime = function(){ if(! owner.hfile) return; var ok,creation,access,write = GetFileTime(owner.hfile,..fsys.time() ,..fsys.time() ,..fsys.time() ) return { creation = creation; access = access; write = write }; }; setTime = function(tm){ if(! owner.hfile) return; if( type(tm) != type.table ) error("参数必须是一个表对象",2); owner.setFileTime( creation = fsys.time().fromSystemTime(tm.creation).utc(); access = fsys.time().fromSystemTime(tm.access).utc(); write = fsys.time().fromSystemTime(tm.write).utc(); ) }; getTime = function(){ var tm = owner.getFileTime(); if(tm) return { creation = tm.creation.toSystemTime(); access = tm.access.toSystemTime(); write = tm.write.toSystemTime() }; }; lastModified = function(){ var tm = owner.getFileTime(); if(tm) return tm.write.toGmtTime(); }; size = function(){ if(owner.hfile){ var low,high = GetFileSize(owner.hfile,0) return tonumber( ..math.size64(low,high) ); } }; size64 = function(){ if(owner.hfile){ var low,high = GetFileSize(owner.hfile,0) return ..math.size64(low,high); } }; deviceIoControl = function(ctlCode,ib,ob,iLen){ var oLen,rLen = 0,{INT n}; if( iLen== null ){ if( ib[["_struct"]] ) iLen = ..raw.sizeof(ib); else iLen = #ib; } if( ob[["_struct"]] ) oLen = ..raw.sizeof(ob); else oLen = #ob; if( ::Kernel32.DeviceIoControl(owner.hfile,ctlCode,ib,iLen,ob,oLen,rLen,null) ) return true,rLen.n; }; type = function(){ return ::Kernel32.GetFileType(owner.hfile); }; handle = { _get = function(){ return owner.hfile; } }; _topointer = function(){ return owner.hfile; }; _serialize = function(kernelCall){ if(kernelCall) return ..raw.serializeDupHandle("fsys.file",owner.hfile); }; ); namespace _metaProperty{ getFileTimes = getTime; setFileTimes = setTime; } is = function(v){ return v@ == _metaProperty; } import fsys.time; CreateFile = ::Kernel32.api("CreateFile","pointer(ustring path,int access,int sharemode,struct secAttrib,int creationDisposition,int flagsAndAttributes,pointer template)") llseek = ::Kernel32.api("_llseek","int(POINTER file,int off,int mode)") SetFilePointerEx = ::Kernel32.api("SetFilePointerEx","bool(POINTER file,long distance,long &offset, INT mode)") ReadByte = ::Kernel32.api("ReadFile","bool(POINTER file,BYTE& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") ReadFile = ::Kernel32.api("ReadFile","bool(POINTER file,string& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") ReadStruct = ::Kernel32.api("ReadFile","bool(POINTER file,struct& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") ReadBuffer = ::Kernel32.api("ReadFile","bool(POINTER file,POINTER buffer,INT bufferSize,INT& numBytes,pointer overlapped)") WriteFile = ::Kernel32.api("WriteFile","bool(POINTER file,string buffer,INT bufferSize,INT& numBytes,pointer lpOverlapped)") GetFileSize = ::Kernel32.api("GetFileSize","INT(POINTER file,int& INT)") FlushFileBuffers = ::Kernel32.api("FlushFileBuffers","int(POINTER file)") SetEndOfFile = ::Kernel32.api("SetEndOfFile","bool(pointer file)"); GetFileTime = ::Kernel32.api("GetFileTime","int(pointer file,struct& creation,struct& access,struct& write)") SetFileTime = ::Kernel32.api("SetFileTime","int(pointer file,struct creation,struct access,struct write)") _seekMode = { ["cur"] = 1/*_FILE_CURRENT*/; ["end"] = 2/*_FILE_END*/; ["set"] = 0/*_FILE_BEGIN*/; } temp = function( path,dontDelete){ if(!path || path[1]=='.'#){ path = ..io.tmpname(,path) } return ..fsys.file(path,"w+b",7/*_FILE_SHARE_READ | _FILE_SHARE_WRIT | _FILE_SHARE_DELETE*/,, 0x100/*_FILE_ATTRIBUTE_TEMPORARY*/ | (!dontDelete ? 0x4000000/*_FILE_FLAG_DELETE_ON_CLOSE*/ : 0) ); } lines = function(path){ var file = ..fsys.file(path,"r"); if(!file) error("打开文件失败",2); return function(){ var s = file.read(); return s; },function() { file.close(); } } lastModified = function(path,last){ var file = ..fsys.file(path,"r"); if(!file) return; var tmWrite = file.lastModified(); file.close(); if(last) return tmWrite > ..time.iso8601(last); if(tmWrite) return tmWrite; } write = ..io.file.write; //@Deprecated read = ..io.file.read; //@Deprecated } /**intellisense() fsys.file = 用于打开或创建文件对象。\nfsys.file 是对系统 API CreateFile(CreateFileW)的封装,\nfsys.file 对象作为原生 API 函数的参数时会自动转换为系统文件句柄(原生 类型pointer)。\n使用 fsys.file 创建的的文件对象可传入其他线程使用(共享文件句柄)。 fsys.file.temp(.(pathOrExt,dontDeleteOnClose) = 创建临时文件,\n可选用 @pathOrExt 参数指定临时文件路径或后缀名,\n指定临时文件后缀名时第一个字符必须是 . 号,\n可选指定 @dontDeleteOnClose 参数值为 true 禁止关闭对象自动删除文件,\n@dontDeleteOnClose 为 true 时文件才会有共享读写权限,\n可通过返回文件对象的 path 属性获取临时文件路径 fsys.file.temp() = !fsysfile. fsys.file.lastModified(__) = 参数 @1 指定文件路径,返回文件最后修改时间。\n返回值是 time.gmt 对象,即 RFC1123 格式时间。HTTP 协议使用该对象\n!time. fsys.file.lastModified(__,"2024/1/1 11:01:00") = 参数 @1 指定文件路径,\b参数 @2 指定任何可作为 time.iso8601 参数的时间格式,可指定字符串。\n如果文件修改时间大于参数 @2 指定的时间则返回 true fsys.file(__/*文件句柄*/) = 可以指定文件、管道等句柄 fsys.file(__/*文件句柄*/,true) = 直接文件、管道等句柄\n添加析构函数负责释放句柄 fsys.file("__/*文件路径*/") = 只读模式打开,文件必须存在\n如果路径以斜杠结束,则以目录模式打开.\n更多参数参考源码 fsys.file("__/*文件路径*/","r+") = 读写模式打开,文件必须存在\n文件路径也可以指定一个目录,可使用返回对象读写目录时间属性,\n更多参数参考源码 fsys.file("__/*文件路径*/","w") = 只写模式打开,创建新文件清空原文件 fsys.file("__/*文件路径*/","w+") = 读写模式打开,创建新文件清空原文件 fsys.file("__/*文件路径*/","w+D") = 读写模式打开临时文件,关闭对象时自动删除文件 fsys.file("__/*文件路径*/","a") = 只写追加模式打开,创建新文件保留原文件 fsys.file("__/*文件路径*/","a+") = 读写追加模式打开,创建新文件保留原文件 fsys.file(.(path,mode,shareMode,creation,flagsAndAttributes,secAttrib) = 所有参数可选,\n参数详细用法参考此函数源码与CreateFile参数用法,\nmode参数可指定数值指定打开模式,也可使用与io.file相同规则的描述字符\nshareMode参数默认为 _FILE_SHARE_READ | _FILE_SHARE_WRITE\ncreation参数默认值为 _OPEN_EXISTING\n@flagsAndAttributes 为可选参数,指定文件属性,省略则自动设置此参数\n@secAttrib 不必指定 fsys.file.is(__) = 判断参数是否 fsys.file 对象 !fsysfile.readTo( = 读取直到以指定的字符串结束 !fsysfile.readTo(.('结束串') = 读取直到以指定的字符串结束,返回值不包含结束串,\n该函数每次仅读取一个字节,效率较低 !fsysfile.read(__/*字节数*/) = 读取指定长度的字节\n不支持多参数 !fsysfile.read({int number} ) = 读取结构体\n不支持多参数 !fsysfile.read() = 读取一行文本\n返回文本不包含回车换行符 !fsysfile.read(-1) = 读取所有内容到文件尾部 !fsysfile.read(0) = 是否未到达文件尾。\n如果已经到达文件尾返回 null,否则返回空字符串。\n注意在布尔表达式工 null 等于 false,空字符串等于 true。 !fsysfile.readAll() = 移动指针到文件头,\n读取到文件尾返回全部数据。\n改用 -1 为参数调用 read 函数可自当前位置读取到文件尾。 !fsysfile.lines() = @for line in ??.lines(){ __/*逐行读取文件,循环返回当前行(字符串值)。\n无论是否以文本模式打开,读取数据总是移除回车符与换行符。*/ } !fsysfile.write(__/*字符串*/) = 写入字符串\n参数也可以是数值、结构体 !fsysfile.readBuffer( = 读取数据到 buffer ,成功返回读取长度,失败返回null !fsysfile.readBuffer(.(buffer,读取长度) = 直接读数据到内存\n参数@1可以是 buffer 对象,或内存指针,\n如果是指针则必须指定读取长度,否则长度参数可选\n成功返回读取长度 !fsysfile.writeBuffer( = 写入缓冲区数据,成功返回写入长度,失败返回null !fsysfile.writeBuffer(.(buffer,写入长度) = 直接写数据到内存\n参数@1可以是 buffer 对象、字符串、内存指针。\n如果是指针则必须指定写入长度,否则长度参数可选。\n成功返回写入长度 !fsysfile.seek("end") = 移动指针至结束处\n返回当前位置,返回值大于2GB则为负值,\n获取文件大小推荐使用 size() 函数 !fsysfile.seek("end",__) = 移动至相对结束处的指定偏移量,\n偏移量应当是一个普通数值。 !fsysfile.seek() = 得到当前位置 !fsysfile.seek("cur",__) = 移动至相对当前位置的指定偏移量,\n偏移量应当是一个普通数值。 !fsysfile.seek("set") = 移动指针到开始 !fsysfile.seek("set",__) = 移动至相对开始处的指定偏移量,\n偏移量应当是一个普通数值。\n\n普通数值的整数上限为 8PB,没有可能会写这么大的文件。\n所以偏移量不支持、也不必要使用 math.size64 对象 !fsysfile.path = 返回文件路径 !fsysfile.flush() = 刷新缓冲区 !fsysfile.delete() = 关闭并删除文件 !fsysfile.close() = 关闭文件句柄 !fsysfile.seteof() = 将当前文件位置设为文件末尾,\n用于快速改变文件大小\n成功返回true !fsysfile.size() = 返回文件大小。\nsize 函数表示的容量可以达到 8PB,一般不必要 size64 函数,\nmath.size64 对象主要用于格式化为适合单位表示的文本。 !fsysfile.size64() = 返回文件大小。\n返回值为 math.size64 长整数对象。\n可调用返回对象的 format 函数格式化为适合单位表示的文本。\n!math_size64. !fsysfile.deviceIoControl( = 对设备驱动程序发送控制指令 !fsysfile.deviceIoControl(.(控制码,输入结构体,输出结构体) = 参数可以为空或结构体,\n输出结构体也可以是 raw.buffer 分配的缓冲区,\n成功返回true,以及读取的字节数 !fsysfile.type() = 获取文件对象的类型\n例如控制台,管道,本地文件....等等\n返回值请参考_FILE_TYPE_前缀的常量 !fsysfile.handle = 返回文件句柄 fsys.file() = !fsysfile. !fsysfile.setTime(creation=创建时间;access=访问时间;write=修改时间) = @.setTime(\n creation = time();\n access = time();\n write = time() \n) !fsysfile.getTime() = 返回创建时间、最后修改时间、最后访问时间,\n所有返回时间为 UTC 标准时间\n!filetimes. !fsysfile.setFileTime(creation=创建时间;access=访问时间;write=修改时间) = @.setFileTime(\n creation = fsys.time();\n access = fsys.time();\n write = fsys.time() \n) !fsysfile.getFileTime() = 返回创建时间、最后修改时间、最后访问时间,\n所有返回时间为 UTC 标准时间\n!filefiletimes. !fsysfile.lastModified() = 返回最后修改时间,返回值是time.gmt对象,\n即RFC1123格式时间,HTTP协议使用该对象\n!time. !filetimes.creation = 文件创建时间\n!time. !filetimes.access = 文件最后访问时间\n!time. !filetimes.write = 文件最后修改时间\n!time. !filefiletimes.creation = 文件创建时间\n!fsys_time. !filefiletimes.access = 文件最后访问时间\n!fsys_time. !filefiletimes.write = 文件最后修改时间\n!fsys_time. fsys.file.lines(path) = @for line in fsys.file.lines(__/*请输入逐行读取的文本文件路径*/) { } _FILEOPENORD=@0x600/*_FILEOPENORD*/ _FILE_ATTRIBUTE_ARCHIVE=@0x20/*_FILE_ATTRIBUTE_ARCHIVE*/ _FILE_ATTRIBUTE_COMPRESSED=@0x800/*_FILE_ATTRIBUTE_COMPRESSED*/ _FILE_ATTRIBUTE_DIRECTORY=@0x10/*_FILE_ATTRIBUTE_DIRECTORY*/ _FILE_ATTRIBUTE_HIDDEN=@2/*_FILE_ATTRIBUTE_HIDDEN*/ _FILE_ATTRIBUTE_NORMAL=@0x80/*_FILE_ATTRIBUTE_NORMAL*/ _FILE_ATTRIBUTE_READONLY=@1/*_FILE_ATTRIBUTE_READONLY*/ _FILE_ATTRIBUTE_SYSTEM=@4/*_FILE_ATTRIBUTE_SYSTEM*/ _FILE_ATTRIBUTE_TEMPORARY=@0x100/*_FILE_ATTRIBUTE_TEMPORARY*/ _FILE_BEGIN=@0x0/*_FILE_BEGIN*/ _FILE_CASE_PRESERVED_NAMES=@2/*_FILE_CASE_PRESERVED_NAMES*/ _FILE_CASE_SENSITIVE_SEARCH=@1/*_FILE_CASE_SENSITIVE_SEARCH*/ _FILE_CURRENT=@1/*_FILE_CURRENT*/ _FILE_END=@2/*_FILE_END*/ _FILE_FILE_COMPRESSION=@0x10/*_FILE_FILE_COMPRESSION*/ _FILE_FLAG_BACKUP_SEMANTICS=@0x2000000/*_FILE_FLAG_BACKUP_SEMANTICS*/ _FILE_FLAG_DELETE_ON_CLOSE=@0x4000000/*_FILE_FLAG_DELETE_ON_CLOSE*/ _FILE_FLAG_NO_BUFFERING=@0x20000000/*_FILE_FLAG_NO_BUFFERING*/ _FILE_FLAG_OVERLAPPED=@0x40000000/*_FILE_FLAG_OVERLAPPED*/ _FILE_FLAG_POSIX_SEMANTICS=@0x1000000/*_FILE_FLAG_POSIX_SEMANTICS*/ _FILE_FLAG_RANDOM_ACCESS=@0x10000000/*_FILE_FLAG_RANDOM_ACCESS*/ _FILE_FLAG_SEQUENTIAL_SCAN=@0x8000000/*_FILE_FLAG_SEQUENTIAL_SCAN*/ _FILE_FLAG_WRITE_THROUGH=@0x80000000/*_FILE_FLAG_WRITE_THROUGH*/ _FILE_NOTIFY_CHANGE_ATTRIBUTES=@4/*_FILE_NOTIFY_CHANGE_ATTRIBUTES*/ _FILE_NOTIFY_CHANGE_DIR_NAME=@2/*_FILE_NOTIFY_CHANGE_DIR_NAME*/ _FILE_NOTIFY_CHANGE_FILE_NAME=@1/*_FILE_NOTIFY_CHANGE_FILE_NAME*/ _FILE_NOTIFY_CHANGE_LAST_WRITE=@0x10/*_FILE_NOTIFY_CHANGE_LAST_WRITE*/ _FILE_NOTIFY_CHANGE_SECURITY=@0x100/*_FILE_NOTIFY_CHANGE_SECURITY*/ _FILE_NOTIFY_CHANGE_SIZE=@0x8/*_FILE_NOTIFY_CHANGE_SIZE*/ _FILE_PERSISTENT_ACLS=@0x8/*_FILE_PERSISTENT_ACLS*/ _FILE_SHARE_READ=@1/*_FILE_SHARE_READ*/ _FILE_SHARE_WRITE=@2/*_FILE_SHARE_WRITE*/ _FILE_SHARE_DELETE=@4/*_FILE_SHARE_DELETE*/ _FILE_TYPE_CHAR=@2/*_FILE_TYPE_CHAR*/ _FILE_TYPE_DISK=@1/*_FILE_TYPE_DISK*/ _FILE_TYPE_PIPE=@3/*_FILE_TYPE_PIPE*/ _FILE_TYPE_REMOTE=@0x8000/*_FILE_TYPE_REMOTE*/ _FILE_TYPE_UNKNOWN=@0x0/*_FILE_TYPE_UNKNOWN*/ _FILE_UNICODE_ON_DISK=@4/*_FILE_UNICODE_ON_DISK*/ _FILE_VOLUME_IS_COMPRESSED=@0x8000/*_FILE_VOLUME_IS_COMPRESSED*/ end intellisense**/