একাধিক পাঠ্য ফাইলকে কীভাবে দক্ষতার সাথে বিভক্ত করা যায় মাল্টলাইন রেকর্ডে বিভক্তকরণ?


9

আমার কাছে একটি বড় পাঠ্য ফাইল রয়েছে (যখন gz'ed হয় তখন ~ 50Gb)। ফাইলটিতে 4*Nলাইন বা Nরেকর্ড রয়েছে ; যে প্রতিটি রেকর্ড 4 লাইন নিয়ে গঠিত। আমি এই ফাইলটি প্রতিটি আকারের ইনপুট ফাইলের প্রায় 25% আকারে 4 টি ছোট ফাইলে বিভক্ত করতে চাই। আমি কীভাবে ফাইলটি রেকর্ড সীমানায় বিভক্ত করতে পারি?

একটি নির্লজ্জ পন্থাটি হ'ল zcat file | wc -lলাইন গণনা পাওয়া, সেই সংখ্যাটি 4 দ্বারা ভাগ করে নেওয়া এবং তারপরে ব্যবহার করা split -l <number> file। যাইহোক, এটি দুইবার ফাইলের ওপরে যায় এবং লাইন-কাউন্টারটি অত্যন্ত ধীর (36 মিনিট)। একটি ভাল উপায় আছে কি?

এটি নিকটে আসে তবে আমি যা খুঁজছি তা নয়। গৃহীত উত্তর একটি লাইন গণনাও করে।

সম্পাদনা করুন:

ফাইলটিতে ফাস্টিক ফর্ম্যাটে সিকোয়েন্সিং ডেটা রয়েছে। দুটি রেকর্ড দেখতে দেখতে (বেনামে):

@NxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGCGA+ATAGAGAG
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTTTATGTTTTTAATTAATTCTGTTTCCTCAGATTGATGATGAAGTTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
AAAAA#FFFFFFFFFFFFAFFFFF#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF<AFFFFFFFFFFAFFFFFFFFFFFFFFFFFFF<FFFFFFFFFAFFFAFFAFFAFFFFFFFFAFFFFFFAAFFF<FAFAFFFFA
@NxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGCGA+ATAGAGAG
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxCCCTCTGCTGGAACTGACACGCAGACATTCAGCGGCTCCGCCGCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
AAAAA#FFFFF7FFFFFFAFFFFA#F7FFFFFFFFF7FFFFFAF<FFFFFFFFFFFFFFAFFF.F.FFFFF.FAFFF.FFFFFFFFFFFFFF.)F.FFA))FFF7)F7F<.FFFF.FFF7FF<.FFA<7FA.<.7FF.FFFAFF

প্রতিটি রেকর্ডের প্রথম লাইনটি a দিয়ে শুরু হয় @

EDIT2:

zcat file > /dev/null 31 মিনিট লাগে।

সম্পাদনা 3: কেবল প্রথম লাইনের সাথে শুরু হয় @। অন্য কেউ কখনও হবে না। এখানে দেখুন । রেকর্ডগুলি যথাযথভাবে থাকা দরকার। ফলাফলযুক্ত ফাইলে কিছু যুক্ত করা ঠিক নয়।


একটি একা কত সময় zcat file > /dev/nullনিতে পারে?
চোরোবা

আপনি প্রশ্নযুক্ত ফাইলের একটি ছোট নমুনা সরবরাহ করতে পারেন?
ফ্লোহিমসফ

আপনি বলছেন যে প্রতিটি রেকর্ড শুরু হয় @এবং রেকর্ডে 4 টি লাইন থাকে। এই দুটোই কি পরম? - এবং 2,3,4 লাইনগুলি @কী দিয়ে শুরু হবে ? এবং ফাইলটিতে ফুটার লাইনের কোনও নন-রেকর্ড শিরোনাম আছে?
পিটার.ও

1
আপনি কি এমন কোনও সমাধান খুঁজছেন যা সংকুচিত ইনপুট পরিচালনা করে এবং / অথবা সংক্ষেপিত আউটপুট উত্পাদন করে? আপনি কি সমান আকারের চারটি সংক্ষেপিত ফাইল সন্ধান করছেন?
স্টিফেন কিট

উত্তর:


4

আমি মনে করি না আপনি এটি করতে পারবেন - নির্ভরযোগ্যভাবে নয়, এবং আপনি যেভাবে জিজ্ঞাসা করছেন তা নয়। জিনিসটি হচ্ছে, সংরক্ষণাগারটির সংকোচনের অনুপাত সম্ভবত মাথা থেকে লেজ পর্যন্ত সমানভাবে বিতরণ করা হবে না - সংক্ষেপণ অ্যালগরিদম অন্যদের তুলনায় কিছু অংশে আরও ভাল প্রয়োগ হবে। এটি ঠিক কিভাবে এটি কাজ করে। এবং তাই আপনি সংকুচিত ফাইলের আকারের উপর আপনার বিভক্তিকে ফ্যাক্টর করতে পারবেন না।

আরও কী, gzip4gbs আকারের চেয়ে বড় সংকোচিত ফাইলের মূল আকারটি সংরক্ষণ করা সমর্থন করে না - এটি এটি পরিচালনা করতে পারে না। এবং সুতরাং আপনি একটি নির্ভরযোগ্য আকার পেতে সংরক্ষণাগারটি জিজ্ঞাসা করতে পারবেন না - কারণ এটি আপনাকে বোকা বানাবে।

4 লাইনের জিনিস - এটি সত্যিই খুব সহজ। 4-ফাইলের জিনিস - আমি কেবল জানি না আপনি কীভাবে এটি নির্ভরযোগ্যভাবে করতে পারেন এবং প্রথমদিকে সংরক্ষণাগারটি সঙ্কুচিত আকার ছাড়াই সংগ্রহ না করে আপনি এমনকি এমনকি বিতরণও করতে পারেন with আমি চেষ্টা করি না বলে আপনি করতে পারেন বলে আমি মনে করি না।

যাইহোক, আপনি যা করতে পারেন তা বিভক্ত আউটপুট ফাইলগুলির জন্য সর্বাধিক আকার নির্ধারণ করা হয়েছে এবং নিশ্চিত করুন যে সেগুলি সর্বদা রেকর্ড বাধাগুলিতে নষ্ট হয়। যা আপনি সহজেই করতে পারেন। এখানে একটি ছোট স্ক্রিপ্ট যা gzipআর্কাইভটি বের করে এবং ফ্লাইয়ের প্রতিটি ফাইলকে সঙ্কুচিত / পুনরায় সংক্রামিত করার আগে ddনির্দিষ্ট count=$rptআর্গুমেন্ট সহ কয়েকটি স্পষ্ট পাইপ-বাফারগুলির মাধ্যমে সামগ্রীগুলি পাইপ lz4করে এটি করবে। teeপ্রতিটি বিভাগের স্টাডারের পাশাপাশি সর্বশেষ চারটি লাইন মুদ্রণের জন্য আমি কয়েকটি ছোট পাইপের কৌশলও ছুঁড়েছিলাম ।

(       IFS= n= c=$(((m=(k=1024)*k)/354))
        b=bs=354xk bs=bs=64k
        pigz -d </tmp/gz | dd i$bs o$b |
        while   read -r line _$((n+=1))
        do      printf \\n/tmp/lz4.$n\\n
        { {     printf %s\\n "$line"
                dd count=$c i$b o$bs
        }|      tee /dev/fd/3|lz4 -BD -9 >/tmp/lz4.$n
        } 3>&1| tail -n4 |tee /dev/fd/2 |
                wc -c;ls -lh /tmp/[gl]z*
        done
)

যতক্ষণ না এটি সমস্ত ইনপুট পরিচালনা করে থাকে ততক্ষণে এটি চলতে থাকবে। এটি এটি কিছু শতাংশ দ্বারা ভাগ করার চেষ্টা করে না - যা এটি পেতে পারে না - পরিবর্তে এটি বিভাজনে সর্বাধিক কাঁচা বাইট গণনা অনুযায়ী এটি বিভক্ত হয়। এবং যাইহোক, আপনার সমস্যার একটি বড় অংশ হ'ল আপনি আপনার সংরক্ষণাগারটিতে একটি নির্ভরযোগ্য আকার পেতে পারেন না কারণ এটি অনেক বড় - আপনি যা-ই করুন না কেন, তা আবার করবেন না - এই অংশটি 4gbs এর চেয়ে কম বিভক্ত করুন , হতে পারে. এই ছোট স্ক্রিপ্টটি কমপক্ষে ডিস্কে একটি সঙ্কুচিত বাইট না লিখেই এটি করতে সক্ষম করে।

এখানে প্রয়োজনীয় সংক্ষিপ্ত সংস্করণ রয়েছে - এটি সমস্ত রিপোর্ট স্টাফটিতে যুক্ত করে না:

(       IFS= n= c=$((1024*1024/354))
        pigz -d | dd ibs=64k obs=354xk |
        while   read -r line _$((n+=1))
        do {    printf %s\\n "$line"
                dd count=$c obs=64k ibs=354xk
        }  |    lz4 -BD -9  >/tmp/lz4.$n
        done
)  </tmp/gz

এটি প্রথমটির মতো একই জিনিসগুলি করে, বেশিরভাগ ক্ষেত্রে, এটি সম্পর্কে এটি বলার মতো তেমন কিছুই নেই। এছাড়াও, কম বিশৃঙ্খলা রয়েছে তাই সম্ভবত কী ঘটছে তা দেখা সহজ।

IFS=জিনিসটি কেবল readপুনরাবৃত্তির জন্য একটি লাইন হ্যান্ডেল করার জন্য । আমরা readএক কারণ ইনপুট শেষ হয়ে গেলে আমাদের লুপটি শেষ করতে হবে। এটি আপনার রেকর্ড আকারের উপর নির্ভর করে - যা আপনার উদাহরণ অনুসারে প্রতি 354 বাইট। আমি gzipএটি পরীক্ষা করার জন্য কিছু এলোমেলো ডেটা সহ একটি 4 + জিবি সংরক্ষণাগার তৈরি করেছি।

এলোমেলো তথ্য এইভাবে পাওয়া গেছে:

(       mkfifo /tmp/q; q="$(echo '[1+dPd126!<c]sc33lcx'|dc)"
        (tr '\0-\33\177-\377' "$q$q"|fold -b144 >/tmp/q)&
        tr '\0-\377' '[A*60][C*60][G*60][N*16][T*]' | fold -b144 |
        sed 'h;s/^\(.\{50\}\)\(.\{8\}\)/@N\1+\2\n/;P;s/.*/+/;H;x'|
        paste "-d\n" - - - /tmp/q| dd bs=4k count=kx2k  | gzip
)       </dev/urandom >/tmp/gz 2>/dev/null

... তবে সম্ভবত আপনার এতটা চিন্তা করার দরকার নেই, কারণ আপনার কাছে ইতিমধ্যে ডেটা এবং সমস্ত কিছু রয়েছে। সমাধান ফিরে ...

মূলত pigz- যা তুলনায় কিছুটা দ্রুত পচে যায় বলে মনে হচ্ছে zcat- সঙ্কুচিত স্ট্রিমটি পাইপগুলি, এবং ddবাফারগুলি যে লেখার ব্লকগুলিতে আউটপুট নির্দিষ্টভাবে 354-বাইটের একাধিকের আকারে মাপ দেয়। লুপ হবে readএকটি $lineপরীক্ষা যে ইনপুট এখনো আসার হয়, যা এটিকে হবে প্রতিটি পুনরাবৃত্তির একবার printfপরে printflz4না করে অন্য একটি ddব্লক পড়তে বলা হয় একটি একাধিক এর 354-বাইট বিশেষভাবে মাপের - বাফার উপলব্ধ সঙ্গে সামঞ্জস্য ddপ্রক্রিয়া - সময়কাল জন্য। প্রাথমিকের কারণে পুনরাবৃত্তির জন্য একটি সংক্ষিপ্ত পঠন হবে read $line- তবে এটি কোনও ব্যাপার নয়, কারণ আমরা এটি lz4- আমাদের সংগ্রাহক প্রক্রিয়া - যেভাবেই প্রিন্ট করছি ।

আমি এটি সেট আপ করেছি যাতে প্রতিটি পুনরাবৃত্তি আনুমানিক 1gb সঙ্কুচিত ডেটা পড়বে এবং যে স্ট্রিমটি প্রায় 650Mb বা আরও বেশি সংকোচিত করবে। lz4অন্য যে কোনও দরকারী সংকোচন পদ্ধতির চেয়ে অনেক বেশি দ্রুত - এটি কারণেই আমি এখানে এটি বেছে নিয়েছি কারণ আমি অপেক্ষা করতে পছন্দ করি না। xzপ্রকৃত সংকোচনের সময়ে আরও ভাল কাজ করবে, সম্ভবত, যদিও। তবে একটি বিষয় lz4, এটি প্রায়শই র‍্যাম গতির কাছাকাছি সময়ে সংক্ষেপণ করতে পারে - যার অর্থ আপনি প্রচুর পরিমাণে lz4সংরক্ষণাগারটিকে দ্রুত দ্রবীভূত করতে পারেন কারণ আপনি যেকোনভাবে স্মৃতিতে লিখতে সক্ষম হবেন।

বড়টি পুনরাবৃত্তির জন্য কয়েকটি প্রতিবেদন করে। উভয় লুপ ddস্থানান্তরিত কাঁচা বাইটের সংখ্যা এবং গতি ইত্যাদির প্রতিবেদন মুদ্রণ করবে । বড় লুপটি চক্র প্রতি ইনপুটটির সর্বশেষ 4 টি লাইন এবং একই জন্য একটি বাইট গণনাও মুদ্রণ করবে, তারপরে lsআমি lz4আর্কাইভগুলি যে ডিরেক্টরিতে লিখি তার একটি নির্দেশিকা অনুসরণ করবে । এখানে কয়েক দফা আউটপুট দেওয়া হচ্ছে:

/tmp/lz4.1
2961+1 records in
16383+1 records out
1073713090 bytes (1.1 GB) copied, 169.838 s, 6.3 MB/s
@NTACGTANTTCATTGGNATGACGCGCGTTTATGNGAGGGCGTCCGGAANGC+TCTCTNCC
TACGTANTTCATTGGNATGACGCGCGTTTATGNGAGGGCGTCCGGAANGCTCTCTNCCGAGCTCAGTATGTTNNAAGTCCTGANGNGTNGCGCCTACCCGACCACAACCTCTACTCGGTTCCGCATGCATGCAACACATCGTCA
+
I`AgZgW*,`Gw=KKOU:W5dE1m=-"9W@[AG8;<P7P6,qxE!7P4##,Q@c7<nLmK_u+IL4Kz.Rl*+w^A5xHK?m_JBBhqaLK_,o;p,;QeEjb|">Spg`MO6M'wod?z9m.yLgj4kvR~+0:.X#(Bf
354

-rw-r--r-- 1 mikeserv mikeserv 4.7G Jun 16 08:58 /tmp/gz
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:32 /tmp/lz4.1

/tmp/lz4.2
2961+1 records in
16383+1 records out
1073713090 bytes (1.1 GB) copied, 169.38 s, 6.3 MB/s
@NTTGTTGCCCTAACCANTCCTTGGGAACGCAATGGTGTGANCTGCCGGGAC+CTTTTGCT
TTGTTGCCCTAACCANTCCTTGGGAACGCAATGGTGTGANCTGCCGGGACCTTTTGCTGCCCTGGTACTTTTGTCTGACTGGGGGTGCCACTTGCAGNAGTAAAAGCNAGCTGGTTCAACNAATAAGGACNANTTNCACTGAAC
+
>G-{N~Q5Z5QwV??I^~?rT+S0$7Pw2y9MV^BBTBK%HK87(fz)HU/0^%JGk<<1--7+r3e%X6{c#w@aA6Q^DrdVI0^8+m92vc>RKgnUnMDcU:j!x6u^g<Go?p(HKG@$4"T8BWZ<z.Xi
354

-rw-r--r-- 1 mikeserv mikeserv 4.7G Jun 16 08:58 /tmp/gz
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:32 /tmp/lz4.1
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:35 /tmp/lz4.2

gzip -lকেবল <2GiB আনপ্রেসড ফাইল আইআইআরসি (যেভাবেই ওপি'র ফাইলের চেয়ে ছোট কিছু) জন্য কাজ করে।
স্টাফেন চেজেলাস

@ স্টাফেনচেজেলাস - জঘন্য। এটিই একমাত্র উপায় যেটি আমি একটি সঙ্কুচিত আকার নেওয়ার পক্ষে চিন্তা করতে পারি। তা ছাড়া, এটি কিছুতেই কাজ করে না।
মাইকজারভেজ

4

রেকর্ড সীমানায় ফাইল বিভক্ত করা আসলে খুব সহজ, কোনও কোড ছাড়াই:

zcat your_file.gz | split -l 10000 - output_name_

এটি প্রতিটি 10000 লাইনের আউটপুট ফাইল তৈরি করবে, যার সাথে আউটপুট_নাম_আআ, আউটপুট_নাম_্যাব, আউটপুট_নাম_এ্যাক, ... আপনার বড় আকারের একটি ইনপুট রয়েছে, এটি আপনাকে প্রচুর আউটপুট ফাইল দেবে। 10000চারটির যে কোনও একাধিকের সাথে প্রতিস্থাপন করুন এবং আপনি নিজের পছন্দ অনুযায়ী আউটপুট ফাইলগুলি বড় বা ছোট করতে পারবেন। দুর্ভাগ্যক্রমে, অন্যান্য উত্তরগুলির মতো, গ্যারান্টি দেওয়ার কোনও ভাল উপায় নেই যে আপনি ইনপুট সম্পর্কে কিছু অনুমান না করেই পছন্দসই সংখ্যা (প্রায়) সমান আকারের আউটপুট ফাইল পাবেন। (বা আসলে পুরো জিনিসটি পাইপিংয়ের জন্য wc।) যদি আপনার রেকর্ডগুলি প্রায় সমান আকারের হয় (বা কমপক্ষে প্রায় সমানভাবে বিতরণ করা হয়) আপনি এটির মতো অনুমান করার চেষ্টা করতে পারেন:

zcat your_file.gz | head -n4000 | gzip | wc -c

এটি আপনাকে আপনার ফাইলের প্রথম 1000 টি রেকর্ডের সংকুচিত আকারটি বলবে। তার উপর ভিত্তি করে, আপনি সম্ভবত প্রতিটি ফাইলের মধ্যে চারটি ফাইলের সমাপ্তি কত সারি চান তার একটি অনুমান নিয়ে আসতে পারেন। (যদি আপনি পঞ্চম ফাইলটি অবশেষে বাকী থাকতে চান না, তবে আপনার অনুমানটি খানিকটা প্যাড করতে ভুলবেন না, বা পঞ্চম ফাইলটি চতুর্থটির লেজকে টেক করার জন্য প্রস্তুত থাকুন))

সম্পাদনা করুন: আপনি সংকুচিত আউটপুট ফাইলগুলি চান তা ধরে নিয়ে এখানে আরও একটি কৌশল রয়েছে:

#!/bin/sh

base=$(basename $1 .gz)
unpigz -c $1 | split -l 100000 --filter='pigz -c > _$FILE.gz' - ${base}_

batch=$((`ls _*.gz | wc -l` / 4 + 1))
for i in `seq 1 4`; do
  files=`ls _*.gz | head -$batch`
  cat $files > ${base}_$i.gz && rm $files
done

এটি অনেকগুলি ছোট ফাইল তৈরি করবে এবং তারপরে দ্রুত এগুলি আবার একত্রিত করবে। (আপনার ফাইলগুলিতে রেখাগুলি কত দীর্ঘ থাকে তার উপর নির্ভর করে আপনাকে -l প্যারামিটারটি টুইঙ্ক করতে হতে পারে)) এটি ধরে নিয়েছে যে আপনার কাছে GNU কোর্টিলস (বিভাজন - ফিল্টার জন্য) এর তুলনামূলক সাম্প্রতিক সংস্করণ রয়েছে এবং আপনার ইনপুট ফাইলের আকারের প্রায় 130% রয়েছে বিনামূল্যে ডিস্ক স্থান। যদি আপনার কাছে না থাকে তবে পিগজ / আনপিগের জন্য জিজিপ / জেক্যাট বিকল্প করুন। আমি শুনেছি কিছু সফ্টওয়্যার লাইব্রেরি (জাভা?) এইভাবে জিজিপ ফাইলগুলি হ্যান্ডেল করতে পারে না, তবে এ পর্যন্ত আমার কোনও সমস্যা হয়নি। (পিগজ একইভাবে কৌশলটি সংক্ষেপণের জন্য ব্যবহার করে))


যদি আপনি পিগজ ইনস্টল করেন তবে আপনি 'জ্যাজ্যাট' এর জন্য 'পিগজ-সিডি' প্রতিস্থাপন করে জিনিসগুলিকে সামান্য কিছুটা বাড়িয়ে দিতে পারেন।
ড্র

2
আহ, আমি এখনই লক্ষ্য করেছি যে আপনি ইতিমধ্যে প্রশ্নে বিভক্তির কথা উল্লেখ করেছেন। তবে সত্যই, কোনও সমাধান সম্পর্কে হুডের নীচে বিভক্ত হিসাবে একই জিনিস সম্পর্কে করা হতে চলেছে। হার্ড অংশটি প্রতিটি ফাইলে আপনাকে কত সারি লাগাতে হবে তা নির্ধারণ করছে।
ড্রং

3

গুগল-গোলকটি যাচাই করার পরে এবং 7..৮ গিগাবাইট .gzফাইল পরীক্ষা করার পরে আমি যা সংগ্রহ করি তা থেকে মনে হয় যে মূল আনসপ্রেসড ফাইলের আকারের মেটাডেটা বড় ফাইলগুলির জন্য সঠিক নয় (যেমন ভুল ) .gz(4 জিবিবি-র চেয়ে কিছু বেশি হতে পারে 2GiB কারওর জন্য) সংস্করণসমূহ gzip)।
জিপিপের মেটাডেটার জন্য আমার পরীক্ষা:

* The compressed.gz file is  7.8 GiB ( 8353115038 bytes) 
* The uncompressed  file is 18.1 GiB (19436487168 bytes)
* The metadata says file is  2.1 GiB ( 2256623616 bytes) uncompressed

সুতরাং এটি দেখে মনে হচ্ছে যে সঙ্কুচিত আকারটি প্রকৃতপক্ষে সঙ্কুচিত না করে (যা কিছুটা মোটামুটি, কিছুটা বলা বাহুল্য) ছাড়াই সম্ভব নয় deter

যাইহোক, এখানে রেকর্ড সীমানায় একটি সঙ্কুচিত ফাইল বিভক্ত করার একটি উপায়, যেখানে প্রতিটি রেকর্ডে 4 টি লাইন থাকে

এটি ফাইলের আকার বাইট (মাধ্যমে stat) এবং awkগণনা বাইট (অক্ষর নয়) সহ ব্যবহার করে। লাইন শেষ হচ্ছে কি না LF| CR| CRLF, এই স্ক্রিপ্টটি বিল্টিন ভেরিয়েবলের মাধ্যমে লাইন সমাপ্তির দৈর্ঘ্য পরিচালনা করে RT)।

LC_ALL=C gawk 'BEGIN{"stat -c %s "ARGV[1] | getline inSize
                      segSiz=int(inSize/4)+((inSize%4)==0?0:1)
                      ouSplit=segSiz; segNb=0 }
               { lnb++; bytCt+=(length+length(RT))
                 print $0 > ARGV[1]"."segNb
                 if( lnb!=4 ) next
                 lnb=0
                 if( bytCt>=ouSplit ){ segNb++; ouSplit+=segSiz }
               }' myfile

নীচে প্রতিটি ফাইলের লাইন গণনা আছে কিনা তা পরীক্ষা করতে আমি ব্যবহার করেছিলাম mod 4 == 0

for i in myfile  myfile.{0..3}; do
    lc=$(<"$i" wc -l)
    printf '%s\t%s\t' "$i" $lc; 
    (( $(echo $lc"%4" | bc) )) && echo "Error: mod 4 remainder !" || echo 'mod 4 ok'  
done | column -ts$'\t' ;echo

পরীক্ষার আউটপুট:

myfile    1827904  mod 4 ok
myfile.0  456976   mod 4 ok
myfile.1  456976   mod 4 ok
myfile.2  456976   mod 4 ok
myfile.3  456976   mod 4 ok

myfile দ্বারা উত্পাদিত হয়েছিল:

printf %s\\n {A..Z}{A..Z}{A..Z}{A..Z}—{1..4} > myfile

2

এই গুরুতর উত্তর হতে বোঝানো হয় না! আমি সবেমাত্র flexটোয়ে যাচ্ছিলাম এবং এটি সম্ভবত ~ 50 জিবি (যদি তা না হয় তবে আমার পরীক্ষার ফাইলের চেয়ে বড় ইনপুট ডেটাতে) ইনপুট ফাইলে কাজ করবে না:

এটি আমার জন্য ~ 1Gb ফাইল ইনপুট.টেক্সটে কাজ করে :

প্রদত্ত flexইনপুট ফাইল splitter.l :

%{
#include <stdio.h>
extern FILE* yyin;
extern FILE* yyout;

int input_size = 0;

int part_num;
int part_num_max;
char **part_names;
%}

%%
@.+ {
        if (ftell(yyout) >= input_size / part_num_max) {
            fclose(yyout);
            if ((yyout = fopen(part_names[++part_num], "w")) == 0) {
                exit(1);
            }
        }
        fprintf(yyout, "%s", yytext);
    }
%%

int main(int argc, char *argv[]) {

    if (argc < 2) {
        return 1;
    } else if ((yyin = fopen(argv[1], "r")) == 0) {
        return 1;
    } else if ((yyout = fopen(argv[2], "w")) == 0) {
        fclose(yyin);
        return 1;
    } else {

        fseek(yyin, 0L, SEEK_END);
        input_size = ftell(yyin);
        rewind(yyin);

        part_num = 0;
        part_num_max = argc - 2;
        part_names = argv + 2;

        yylex();

        fclose(yyin);
        fclose(yyout);
        return 0;
    }
}

উৎপাদিত lex.yy.c করুন এবং এটি কম্পাইল splitterসঙ্গে বাইনারি:

$ flex splitter.l && gcc lex.yy.c -ll -o splitter

ব্যবহার:

$ ./splitter input.txt output.part1 output.part2 output.part3 output.part4

1 জিবি ইনপুট.টেক্সটের জন্য চলমান সময় :

$ time ./splitter input.txt output.part1 output.part2 output.part3 output.part4

real    2m43.640s
user    0m48.100s
sys     0m1.084s

এখানে প্রকৃত লেক্সিংটি এত সহজ, আপনি সত্যিই লেক্স থেকে উপকৃত হন না। কেবল কল করুন getc(stream)এবং কিছু সাধারণ যুক্তি প্রয়োগ করুন। এছাড়াও, আপনি কি জানেন যে (ডট) রেগেক্স অক্ষর (চ) লেক্সে নিউলাইন ছাড়া অন্য কোনও চরিত্রের সাথে মেলে , তাই না? যদিও এই রেকর্ডগুলি মাল্টি-লাইন।
কাজ

@ কাজ যখন আপনার বক্তব্যগুলি সাধারণভাবে সমালোচিত হয় তবে এটি প্রকৃতপক্ষে প্রদত্ত ডেটাগুলির সাথে কাজ করে
ফ্লোহিমসলে

কেবল দুর্ঘটনাক্রমে, কারণ কোনও ডিফল্ট নিয়ম থাকে যখন কিছুই মেলে না: একটি অক্ষর গ্রাস করে আউটপুট থেকে মুদ্রণ করুন! অন্য র‍্যাওয়ার্ডগুলিতে, আপনি নিজের ফাইলটি কেবল এমন একটি নিয়মের সাহায্যে করতে পারেন যা @চরিত্রটিকে স্বীকৃতি দেয় এবং তারপরে ডিফল্ট নিয়মে ডেটা অনুলিপি করতে দেয়। এখন আপনার নিয়মের একটি বড় টোকেন হিসাবে ডেটার অংশটি অনুলিপি করা হয়েছে এবং তারপরে ডিফল্ট নিয়মটি একবারে দ্বিতীয় লাইনটির একটি অক্ষর পেয়েছে।
কাজ

স্পষ্ট করার জন্য ধন্যবাদ। আমি ভাবছি, কীভাবে আপনি এই কাজটি সমাধান করবেন txr
ফ্ল্লোহিমসেফ

আমি নিশ্চিত নই যে আমি করতাম কারণ টাস্কটি খুব দ্রুত পরিমাণে ডেটা সহ খুব সহজ কাজটি করা সম্ভব with
কাজ

1

পাইথনের এখানে একটি সমাধান রয়েছে যা আউটপুট ফাইলগুলি লেখার সাথে সাথে লেখার জন্য একটি ইনপুট ফাইলকে দিয়ে যায়।

ব্যবহার সম্পর্কে একটি বৈশিষ্ট্য wc -lহ'ল আপনি ধরে নিচ্ছেন যে এখানে প্রতিটি রেকর্ড একই আকারের। এটি এখানে সত্য হতে পারে, তবে নীচের সমাধানটি কার্যকর হয় এমনকি যদি এটি না হয়। এটি মূলত ব্যবহার করছে wc -cবা ফাইলটিতে বাইট সংখ্যা number পাইথনে, এটি os.stat () এর মাধ্যমে সম্পন্ন হয়

প্রোগ্রামটি কীভাবে কাজ করে তা এখানে। আমরা প্রথমে আদর্শ বিভাজন পয়েন্টগুলি বাইট অফসেট হিসাবে গণনা করি। তারপরে আপনি ইনপুট ফাইলের লাইনগুলি যথাযথ আউটপুট ফাইলটিতে পড়েন। আপনি যখন দেখেন যে আপনি সর্বোত্তম পরবর্তী বিভাজন বিন্দুটি অতিক্রম করেছেন এবং আপনি একটি রেকর্ড সীমানায় রয়েছেন, শেষ আউটপুট ফাইলের কাছাকাছি এবং পরবর্তীটি খুলুন।

প্রোগ্রামটি এই অর্থে অনুকূল, এটি একবার ইনপুট ফাইলের বাইটগুলি পড়ে; ফাইলের আকার পাওয়ার জন্য ফাইলের ডেটা পড়ার দরকার নেই। প্রয়োজনীয় স্টোরেজ একটি লাইনের আকারের সাথে সমানুপাতিক। পাইথন বা সিস্টেমের সম্ভবত I / O গতি বাড়ানোর জন্য যুক্তিসঙ্গত ফাইল বাফার রয়েছে।

ভবিষ্যতে আপনি এটিকে সামঞ্জস্য করতে চান তবে কতগুলি ফাইল বিভক্ত হবে এবং রেকর্ডের আকারটি কী হবে তার জন্য আমি প্যারামিটার যুক্ত করেছি।

এবং স্পষ্টতই এটি অন্যান্য প্রোগ্রামিং ভাষায়ও অনুবাদ করা যেতে পারে।

অন্য একটি বিষয়, আমি নিশ্চিত নই যে উইন্ডোজ তার ক্রল্ফ সহ লাইনটির দৈর্ঘ্যটি ইউনিক্স-ওয়াই সিস্টেমে ঠিকমত পরিচালনা করে কিনা। যদি লেন () এখানে একের পর এক বন্ধ থাকে তবে আমি আশা করি এটি প্রোগ্রামটি কীভাবে সামঞ্জস্য করবেন এটি সুস্পষ্ট।

#!/usr/bin/env python
import os

# Adjust these
filename = 'file.txt'
rec_size = 4
file_splits = 4

size = os.stat(filename).st_size
splits = [(i+1)*size/file_splits for i in range(file_splits)]
with open(filename, 'r') as fd:
    linecount = 0
    i = 0 # File split number
    out = open('file%d.txt' % i, 'w')
    offset = 0  # byte offset of where we are in the file: 0..size
    r = 0 # where we are in the record: 0..rec_size-1
    for line in fd:
        linecount += 1
        r = (r+1) % rec_size
        if offset + len(line) > splits[i] and r == 1 :
            out.close()
            i += 1
            out = open('file%d.txt' % i, 'w')
        out.write(line)
        offset += len(line)
    out.close()
    print("file %s has %d lines" % (filename, linecount))

এটি কোনও রেকর্ড সীমানায় বিভক্ত নয়। যেমন। প্রথম উপ-ফাইল বিভাজনটি এই printf %s\\n {A..Z}{A..Z}{A..Z}{A..Z}—{1..4}
ইনপুটটির

1

ব্যবহারকারী FloHimself একটি সম্পর্কে জানতে আগ্রহী করলো TXR সমাধান। এম্বেড করা টিএক্সআর লিস্প ব্যবহার করে এখানে একটি :

(defvar splits 4)
(defvar name "data")

(let* ((fi (open-file name "r"))                 ;; input stream
       (rc (tuples 4 (get-lines fi)))            ;; lazy list of 4-tuples
       (sz (/ (prop (stat name) :size) splits))  ;; split size
       (i 1)                                     ;; split enumerator
       (n 0)                                     ;; tuplecounter within split
       (no `@name.@i`)                           ;; output split file name
       (fo (open-file no "w")))                  ;; output stream
  (whilet ((r (pop rc)))  ;; pop each 4-tuple
    (put-lines r fo) ;; send 4-tuple into output file
    ;; if not on the last split, every 1000 tuples, check the output file
    ;; size with stat and switch to next split if necessary.
    (when (and (< i splits)
               (> (inc n) 1000)
               (>= (seek-stream fo 0 :from-current) sz))
      (close-stream fo)
      (set fo (open-file (set no `@name.@(inc i)`) "w")
           n 0)))
  (close-stream fo))

মন্তব্য:

  1. একই কারণে popটিপলসের অলস তালিকা থেকে প্রতিটি টিপলকে প্যাপ করা গুরুত্বপূর্ণ, যাতে অলস তালিকাটি গ্রাস করা যায়। আমাদের অবশ্যই সেই তালিকা শুরুর কোনও রেফারেন্স ধরে রাখতে হবে না কারণ ফাইলের মধ্য দিয়ে যাওয়ার পরে স্মৃতিশক্তি বৃদ্ধি পাবে।

  2. (seek-stream fo 0 :from-current)এটি কোনও অপ-কেস কেস নয় seek-stream, যা বর্তমান অবস্থানে ফিরে এসে নিজেকে দরকারী করে তোলে।

  3. পারফরম্যান্স: এটি উল্লেখ করবেন না। ব্যবহারযোগ্য, তবে কোনও ট্রফি ঘরে আনবে না।

  4. যেহেতু আমরা প্রতি 1000 টি টিউপস আকারটি যাচাই করি, আমরা কেবল টিউপল আকার 4000 লাইন তৈরি করতে পারি।


0

আপনার যদি নতুন ফাইলগুলির মূল ফাইলের সংলগ্ন অংশগুলির প্রয়োজন না হয় তবে sedআপনি এটি নিম্নলিখিত পদ্ধতিতে পুরোপুরি করতে পারেন :

sed -n -e '1~16,+3w1.txt' -e '5~16,+3w2.txt' -e '9~16,+3w3.txt' -e '13~16,+3w4.txt'

-nপ্রতিটি লাইনে মুদ্রণ থেকে এটা স্টপ, এবং প্রতিটি -eস্ক্রিপ্ট মূলত একই জিনিস করছে। 1~16প্রথম লাইন এবং তার পরে প্রতি 16 তম লাইনে মেলে। ,+3এর অর্থ প্রতিটির পরের তিনটি লাইনের সাথে মেলে। w1.txtবলে যে সমস্ত লাইন ফাইলটিতে লিখুন 1.txt। এটি 4 টি লাইনের প্রতিটি চতুর্থ গোষ্ঠী নিচ্ছে এবং 4 টি লাইনের প্রথম গ্রুপের সাথে শুরু করে একটি ফাইলে এটি লিখছে। অন্য তিনটি কমান্ড একই কাজ করে তবে তারা প্রতিটি 4 টি লাইনে এগিয়ে চলেছে এবং একটি আলাদা ফাইলে লিখবে।

এটি আপনার মারাত্মকভাবে ভেঙে যাবে যদি ফাইলটি আপনার নির্দিষ্ট করা নির্দিষ্টকরণের সাথে মেলে না তবে অন্যথায় এটি আপনার ইচ্ছা অনুসারে কাজ করা উচিত। আমি এটির প্রোফাইল দিইনি, সুতরাং এটি কতটা দক্ষ হবে তা আমি জানি না তবে sedস্ট্রিম সম্পাদনায় যুক্তিসঙ্গতভাবে দক্ষ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.