سلام
بفرمایید بچه ها تبدیل به تابع کردم که کار کردن باهاش راحت هه :
برای تیکه کردن و برش فایل :
کد:function SpliteFile(SourceFile, DestinationFileSplited, CharacterSpliteCount, FileBinary) if (FileBinary~=nil and (FileBinary=="" or FileBinary=="text" or FileBinary=="Text" or FileBinary=="t" or FileBinary=="T")) then FileBinary = ""; else FileBinary = "b"; end local openForReadHandle, err = io.open(SourceFile, "r"..FileBinary); if (openForReadHandle==nil) then return nil, err; end local destinationSplite = String.SplitPath(DestinationFileSplited); if (destinationSplite==nil or destinationSplite.Drive=="" or destinationSplite.Folder=="" or destinationSplite.Filename=="" or destinationSplite.Extension=="") then return nil; end local destinationFileNameInitialize = destinationSplite.Drive..destinationSplite.Folder..destinationSplite.Filename; local splitedAllFilesPath = {}; Counter = 1; while (true) do local readContent = openForReadHandle:read(CharacterSpliteCount); if (readContent~=nil) then destinationFilePath = destinationFileNameInitialize..Counter..destinationSplite.Extension; local openForSaveHandle, err = io.open(destinationFilePath, "w"..FileBinary); if (openForSaveHandle==nil) then readContent = nil; collectgarbage(); return nil, err; end openForSaveHandle:write(readContent); openForSaveHandle:close(); readContent = nil; collectgarbage(); splitedAllFilesPath[Counter] = destinationFilePath; Counter = Counter + 1; else break; end end openForReadHandle:close(); readContent = nil; collectgarbage(); return splitedAllFilesPath; end
توضیحات :
کد:--table SpliteFile(string SourceFile, string DestinationFileSplited, number CharacterSpliteCount [, string FileBinary]); => resault : table SplitedFilesPath
تابع SpliteFile :
آرگومان ها :
اولین ورودی (SourceFile) رشته ای هست از مسیر کامل فایلی که میخواین برش بدین (همراه نام و پسوند فایل)
دومین ورودی (DestinationFileSplited) رشته ای هست از مسیر کامل فایل که میخواین تیکه بشه (همراه نام و پسوند فایل) . نکته اینکه نام فایل خودش شماره گذاری میشه اتوماتیک بعد از بریده شدن
*** سومین ورودی (CharacterSpliteCount) عدد هست که تعداد کاراکترهایی که توی هر فایل باید نوشته بشه رو بهش میدین . اینکه بر اساس حجم داده شه ، خودتون جداگانه محاسبه کنین که هر کاراکتر که 8 بیت اشغال میکنه ، این عدد رو چند باید بدین تا به اندازه ی حجم مورد نظرتون بریده شه . فقط اینکه هر 160 میلیون (160000000) کاراکتر ، حجم 152 مگابایت میشه یعنی آرگومان سوم تون رو 160000000 بدین ، هر قسمت از فایل مورد نظرتون که تیکه شد ، 152 مگابایت میشه . و اینکه این عدد یعنی حجم هر فایل اگه بزرگتر باشه ، نوشتن فایل ها سریعتر انجام میشه و برنامه زودتر عمل اش رو انجام میده
*** تذکر مهم : سعی کنین این عدد یعنی سومین ورودی رو بزرگتر از 100 میلیون ندین چون متغییرهای لوا مثل سی شارپ نیست که ظرفیت اش تا اندازه ای که رم طرف جواب داد ، جا بشه یعنی متغییرهای لوا (حداقل نسخه 5.1) ظرفیت محدودی دارن و بیشتر از این احتمال جا نشدن همه ی کاراکترها توشون هست و اگه جا نشن ، ارور میدن که عملیات کنسل میشه . با این حال تا 200 میلیون رو که تست کردم مشکلی نداشت اما بیشتر از این ارور میداد . کلا پیشنهاد من اینه که 100 تا 150 میلیون بیشتر ندین که در این صورت ، تقریبا هر تیکه از فایل 90 تا 140 مگابایت میشه
هر چی این عدد بیشتر بشه مشخصه که متغییر باید توش بیشتر جا بشه و بنابراین نیاز به رم بیشتر میشه (200 میلیون کاراکتر اگه بدین فکر کنم حداقل 2 تا 4 گیگ رم خالی نیاز داشته باشه)
دقت کنین که شما ممکنه تا 300 میلیون هم برای این عدد بدین و موقع برش دادن مشکلی پیش نیاد ولی موقع ادغام کردن ، مشکل ایجاد میشه پس هر عددی که دادین ، بعدش ادغام کنین فایل را ببینین مشکلی پیش نیاد و اگه مشکل Memory Not Enough داد ، این عدد رو کم کنین . البته همونطور که گفته شد باید برای کار با فایل ها ، حافظه ی خالی در رم طرف رو چک کنین که به اندازه ی کافی فضای خالی داشته باشه که این مقدار کاراکتر (برای 200 میلیون ،2 گیگ رم خالی فکر کنم حداقل بخواد) توش جا بشه
*** کلا 150 تا 170 میلیون احتمالش خیلی کمه که ارور بده و هر چی عدد رو کمتر کنین (البته به رم خالی طرف هم بستگی داره) احتمال ارورش هنوز کم و کمتر میشه ولی طرف اگه هر چقدر رم خالی داشته باشه (مثلا 13 گیگ) ، بخاطر ظرفیت محدود متغییرهای لوا و همینطور 32 بیتی بودن اتوپلی (و در نتیجه 32 بیتی بودن پروژه مون) بیشتر از 200 میلیون کاراکتر توی متغییرمون جا نمیشه
چهارمین ورودی (FileBinary) که اختیاری هست و رشته ای هست که مشخص میکنه فایل مورد نظر باینری هست یا نه . 99 درصد فایل ها یعنی فایل هایی بجز فایل های txt ای که خودمون مینویسیم (نه اینکه هر فایلی که پسوند txt داره ، باینری نباشه ها) (فایل word و pdf منظورم نیست ها) که باینری نیستن ، بقیه یعنی همون 99 درصد فایل ها باینری هستن . یعنی فایل های exe و pdf و word و وییدئو و تصویر و ... همه شون باینری هستن . اگه فایل مورد نظرتون ، فایل باینری هست ، لازم نیست اصلا این آرگومان رو پر کنین و لازم نیست اصلا هیچ چی بدین (پر نکردن یا دادن nil فرقی ندارن با هم . فقط دقت کنید که nil دادن با رشته ی خالی یعنی "" دادن فرق داره) . اگه هم فایل تون باینری نیست ، فقط کافیه رشته ی خالی یا رشته ی "t" یا "text" بدین در این آرگومان
خروجی تابع :
یک آرایه (splitedAllFilesPath) که مسیر کامل تک تک فایل های تیکه و برش داده شده هست رو برمیگردونه . اگه ارور داده شه ، تابع nil رو در اولین متغییر و در صورتی که مشکل از تابع Open باشه ، پیام ارور رو بصورت رشته برمیگردونه.
*** تذکر : بعد از اجرای این تابع یا تابع پایین ، برای اینکه متغییرهای محلی تابع ، فضای اشغال شده شون از رم پاک شه ، از تابع collectgarbage() بدون ورودی استفاده کنین
برای ادغام فایل های بریده شده در یک فایل واحد :
توضیحات :کد:function MergeFiles(SplitedFilesPath, DestinationFileMerge, FileBinary) if (FileBinary~=nil and (FileBinary=="" or FileBinary=="text" or FileBinary=="Text" or FileBinary=="t" or FileBinary=="T")) then FileBinary = ""; else FileBinary = "b"; end local openForSaveHandle, err = io.open(DestinationFileMerge, "a"..FileBinary); if (openForSaveHandle==nil) then return nil, err end for i=1,#SplitedFilesPath do local openForReadHandle, err = io.open(SplitedFilesPath[i], "r"..FileBinary); if (openForReadHandle==nil) then return nil, err end readContent = openForReadHandle:read("*a"); openForSaveHandle:write(readContent); openForReadHandle:close(); end openForSaveHandle:close(); readContent = nil; collectgarbage(); end
کد:--MergeFiles(table mySplitedFilesPath, string DestinationFileMerge [, string FileBinary])
تابع MergeFiles :
آرگومان ها :
ورودی اول (SplitedFilesPath) ، یک آرایه ی رشته ای حاوی مسیر کامل تمام فایل های مبدا که همون فایل های تیکه و جدا شده هست ، هست (خروجی تابع SpliteFile در صورت موفقیت ، همچین آرایه ای رو برمیگردونه) (همراه نام و پسوند دونه دونه ی فایل های جدا شده)
ورودی دوم (DestinationFileMerge) رشته ای حاوی مسیر کامل فایل مقصد یا فایل واحد ای که میخواین ادغام کنین (همراه نام و پسوند فایل)
ورودی سوم (FileBinary) که همون ورودی آخر تابع SpliteFile هست که در بالا توضیح داده شد و اختیاری هست (بصورت پیش فرض برای فایل های باینری هه)
*** نکته : فایل های تیکه شده ، بسته به اینکه چه نوع فایل و با چه پسوندی باشن ، میتونین با اونکه جدا هم هستن اجرا بشن یا نه مثلا اگه فایل های ویدئویی با پسوند ویدئویی رو بصورت تیکه شده ذخیره کنین ، هر تیکه میشه مستقل اجرا بشه ولی اگه با پسوند ویدئویی ذخیره نکین ، مثل حالت عادی چون پسوندش فرق داره ، ممکنه توسط بعضی از پلیرها اجرا نشه ولی محتوای فایل درست هست حالا میخواد با هر پسوندی باشه (البته اگه موقع برش فایل مشکلی پیش نیاد که در بالا توضیح داده شد) . اما مشخص هست اگه فایل هایی مثل فایل های exe برش داده بشن هر تیکه از فایل های برش داده شده شون اجرا نمیشه و معنا نداره (حتی اگه همه ی تیکه هاش با پسوند exe ذخیره شن) تا زمانی که دوباره این فایل های بریده شده ی exe را در یک فایل واحد دیگه ادغام کنین که اون وقت قابل اجراست
مثال :
کد:mySplitedFilesPath = SpliteFile("G:\\Tolo 6\\narm afzar\\Other Software\\Virtual Tools\\VMware Workstation Pro 12.0.0 Build 2985596\\VMware Workstation Pro 12.exe", _SourceFolder.."\\New folder\\VMware Workstation Pro .exe", 100000000); if (mySplitedFilesPath~=nil) then MergeFiles(mySplitedFilesPath, _SourceFolder.."\\VMware Workstation Pro .exe"); end collectgarbage();






پاسخ با نقل قول
Bookmarks