Kodėl tekstiniai failai baigiasi nauja eilute?

Manau, kad kiekvienas čia yra susipažinęs su patarlė, kad visi tekstiniai failai turėtų baigtis nauja eilute. Apie šią „taisyklę“ jau daugelį metų žinojau, bet visuomet man įdomu - kodėl?

1177
08 апр. Will Robertson rinksis balandžio 8 d 2009-04-08 15:16 '09, 15:16, 2009-04-08 15:16
@ 18 atsakymų

Kadangi POSIX standartas apibrėžia eilutę :

3.206 Linija
Nulinės ar daugiau nei „naujienų“ simbolių seka ir baigiamasis <newline> simbolis.

Todėl linijos, kurios nesibaigia naujos eilutės simboliu, nelaikomos aktualiomis. Štai kodėl kai kurioms programoms sunku apdoroti paskutinę failo eilutę, jei ji nėra baigta nauja eilute.

Dirbant su terminalo emulatoriumi, yra bent vienas pagrindinis privalumas šiai pamokai: visi „Unix“ įrankiai tikisi šio susitarimo ir su juo dirbti. Pvz., Derinant failus su cat failas, baigiantis naujuoju linija, turės kitokį efektą nei failas be:

 $ more a.txt foo $ more b.txt bar $ more c.txt baz $ cat {a,b,c}.txt foo barbaz 

Ir, kaip parodyta ankstesniame pavyzdyje, rodant failą komandinėje eilutėje (pvz., Per more ), failas su galutine linija veda į teisingą ekraną. Netinkamai užpildytas failas gali būti sugadintas (antroji eilutė).

Siekiant nuoseklumo, labai naudinga laikytis šios taisyklės - kitaip bus reikalingas papildomas darbas dirbant su standartiniais Unix įrankiais.


Pagalvokite apie tai kitaip: jei linijos nesibaigia nauja linija, komandų, pavyzdžiui, cat naudingumas yra daug sudėtingesnis: kaip padaryti komandą sujungti failus taip, kad

  1. kiekvienas failas prasideda nauja eilute, kuriai reikia 95% laiko; bet
  2. Tai leidžia sujungti paskutinę ir pirmąją dviejų failų eilutę, kaip nurodyta aukščiau pateiktame pavyzdyje tarp b.txt ir c.txt ?

Žinoma, tai gali būti išspręsta, bet jums reikia padaryti sudėtingesnį cat (pridedant pozicioninius argumentus komandinei eilutei, pavyzdžiui, cat a.txt --no-newline b.txt c.txt ), o dabar - komandą, o ne kiekvieną atskirą asmenį. Failas valdo, kaip jis įterpiamas kartu su kitais failais. Tai beveik neabejotina.

... Arba turite įvesti specialų globėją, kad pažymėtumėte eilutę, kuri turėtų būti tęsiama, o ne užpildyta. Na, dabar jūs esate įstrigę tokioje pačioje situacijoje kaip POSIX, išskyrus apverstą (linijos tęsinys, o ne linijos nutraukimo pobūdis).


Dabar, ne POSIX sistemose (šiuo metu daugiausia „Windows“), tai reiškia, kad failai paprastai nesibaigia nauja eilute, o (neoficialus) eilutės apibrėžimas, pavyzdžiui, gali būti „atskirtas naujuoju eilutės simboliu "(pastaba Accent). Tai visiškai teisinga. Tačiau struktūrizuotiems duomenims (pvz., Programos kodui) tai leidžia suprasti minimaliai sudėtingesnį: tai paprastai reiškia, kad parašai turi būti perrašyti. Jei analizatorius iš pradžių buvo parašytas su POSIX apibrėžimu, tuomet gali būti lengviau keisti simbolių srautą nei analizatorius - kitaip tariant, įvesties pabaigoje pridėkite „dirbtinės linijos tiekimo“ simbolį.

1116
08 апр. atsakymas, kurį pateikė Konradas Rudolphas 2009-04-08 15:46 '09, 15:46, 2009-04-08 15:46

Kiekvieną eilutę turi nutraukti nauja eilutė, įskaitant ir paskutinę. Kai kuriose programose yra sunkumų apdorojant paskutinę failo eilutę, jei ji nėra baigta nauja eilute.

Persijos įlankos bendradarbiavimo taryba įspėja apie tai ne todėl, kad negali apdoroti bylos, bet todėl, kad ji turi būti standarto dalis.

C kalbos standarte šaltinio failas, kuris nėra tuščias, turi baigtis naujuoju eilutės ženklu, kuris neturėtų iš karto sekti backslash simboliu.

Kadangi šis sakinys yra „privalomas“, turime ištaisyti diagnostikos pranešimą, kad būtų pažeista ši taisyklė.

Tai yra ANSI C 1989 standarto 2.1.1.2 skirsnyje, ISO C 1999 standarto 5.1.1.2 skirsnyje (ir galbūt ir ISO C 1990 standarte).

Nuoroda: GCC / GNU pranešimų archyvas .

256
08 апр. Atsakymą pateikė Bill the Lizard balandžio 8 d 2009-04-08 15:26 '09, 15:26, 2009-04-08 15:26

Šis atsakymas yra bandymas gauti techninį atsakymą, o ne nuomonę.

Jei norime būti POSIX puristais, apibrėžiame eilutę kaip:

Nulinio ar daugiau simbolių seka ir lt; nauji simboliai> plius galutinis <nauja eilutės simbolis.

Šaltinis: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

Neišsami linija:

Vienos ar daugiau simbolių seka failo pabaigoje nėra abėcėlės tvarka.

Šaltinis: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

Tekstinis failas kaip:

Failas su simboliais, išdėstytais nuliais ar daugiau linijų. Stygose nėra NUL simbolių, ir nė vienas iš jų negali viršyti {LINE_MAX} baitų ilgio, įskaitant <newline> simbolį. Nors „POSIX.1-2008“ neišskiria tekstinių failų ir dvejetainių failų (žr. ISO C standartą), daugelis komunalinių paslaugų gamina tik nuspėjamą ar reikšmingą išėjimą, kai dirbama su tekstiniais failais. Standartinės komunalinės paslaugos, turinčios tokius apribojimus, visada nurodo „tekstinius failus“ jų skyriuose „STDIN“ arba „INPUT FILES“.

Šaltinis: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

Linija kaip:

Konjuguoti baitų seką, baigiant ir įtraukiant pirmąjį nulinį baitą.

Šaltinis: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

Iš to galime daryti išvadą, kad vienintelis laikas, kai susidursime su bet kokios rūšies problema, yra tai, kad mes nagrinėjame failo eilutės ar failo sąvoką kaip tekstinį failą (nes tekstinis failas organizuoja nulines ar daugiau linijų, o linija, kurią žinome turi baigtis <newline>).

Pavyzdys: wc -l filename .

wc vadovo skaitome:

Styga apibrėžiama kaip simbolių eilutė, pažymėta simboliu <newline>.

Kokios yra „JavaScript“, „html“ ir „css“ failų pasekmės, o tada jos yra tekstiniai failai?

Naršyklėse, moderniuose IDE ir kituose priekinės paskirties įrenginiuose nėra problemų, susijusių su EOL praleidimu į EOF. Programos teisingai analizuos failus. Taip yra dėl to, kad ne visos operacinės sistemos atitinka „POSIX“ standartą, todėl įrankiams be operacinės sistemos (pvz., Naršyklės) failų tvarkymas neatitinka POSIX standarto (ar bet kokio OS lygio standarto).

Todėl galime būti tikri, kad EOF EOL turės beveik jokio neigiamo poveikio taikomųjų programų lygiui, nepriklausomai nuo to, ar jis veikia UNIX OS.

Šiame etape galime tvirtai pasakyti, kad dirbant su JS, HTML, CSS kliento pusėje EOL yra saugus. Tiesą sakant, mes galime teigti, kad yra saugu surasti bet kurį iš šių failų, kuriuose nėra <newline>.

Galime imtis dar vieno žingsnio ir pasakyti, kad ji negali laikytis POSIX standarto NodeJS atžvilgiu, nes ji gali veikti aplinkose, kurios nėra suderinamos su POSIX.

Ką mes palikome? Sistemos lygio įrankis.

Tai reiškia, kad vienintelės problemos, su kuriomis susiduriama, yra priemonės, kuriomis siekiama susieti jų funkcionalumą su POSIX semantika (pvz., Eilutės apibrėžimas, kaip parodyta wc ).

Tačiau ne visos korpusai automatiškai prisijungs prie POSIX. Pavyzdžiui, Bash nesilaiko numatytojo POSIX elgesio. Yra jungiklis, įgalinantis jį: POSIXLY_CORRECT .

Maistas, skirtas galvoti apie EOL reikšmę, kurią <newline>: http://www.rfc-editor.org/EOLstory.txt

Laikykitės instrumentinės trasos dėl visų praktinių tikslų ir tikslų:

Leiskite dirbti su failu, kuriame nėra EOL. Šio rašymo metu šiame pavyzdyje rodomas miniatiūrinis javascript be EOL.

 curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js $ cat x.js y.js > z.js -rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 x.js -rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 y.js -rw-r--r-- 1 milanadamovsky 15810 Aug 14 23:18 z.js 

Atkreipkite dėmesį, kad cat failo dydis yra tiksliai atskirų jos dalių suma. Jei „JavaScript“ failų sujungimas yra problema, susijusi su „js“ failais, tinkamesnė užduotis būtų paleisti kiekvieną „JavaScript“ failą kabliataškiu.

Kaip kažkas paminėjo šioje temoje: ką daryti, jei norite, kad cat dvi bylas, kurių produkcija būtų tik viena eilutė vietoj dviejų? Kitaip tariant, cat daro tai, ką reikia daryti.

cat man pamini tik skaitymo įvedimą į EOF, o ne <newline>. Atkreipkite dėmesį, kad -n cat jungiklis taip pat spausdina liniją su linija, kurioje yra galinė linija (arba neišsami linija) - tai yra tas, kurį skaitiklis pradeda su 1 (pagal man ).

-n Išėjimo linijų skaičius, pradedant nuo 1.

Dabar, kai suprantame, kaip POSIX apibrėžia eilutę, šis elgesys tampa dviprasmiškas arba tikrai nesuderinamas.

Tam tikros tikslinės priemonės supratimas ir tinkamumas padės nustatyti, kaip svarbu EOL naudoti gautus failus. C, C ++, Java (JAR) ir kt. Kai kurie standartai nustatys naują eilutę tikslumui - toks standartas neegzistuoja JS, HTML, CSS.

Pavyzdžiui, vietoj wc -l filename galite padaryti wc -l filename awk '{x++}END{ print x}' filename ir įsitikinti, kad užduoties sėkmė nekelia pavojaus failui, kurį galėtume apdoroti (pvz., trečiosios šalies biblioteka, pvz., minimali JS, kurią mes curl ), nebent mes ketiname skaityti eilutes pagal POSIX koncepciją.

Išvada

Realiojo naudojimo atvejų bus labai mažai, kai tam tikriems tekstiniams failams, pvz., JS, HTML ir CSS, EOL perdavimas į EOF turės neigiamą poveikį, jei visai nebus. Jei pasikliaujame <newline> buvimu, mes apribojame mūsų įrankių rinkinio patikimumą tik tiems failams, kuriuos sukūrėme, ir atveriame galimas klaidas, kurias padarė trečiosios šalies failai.

Istorijos moralė: inžinerinė technika, neturinti silpnumo iš EOL EOF.

Nesivaržykite skelbti naudojimo pavyzdžius, nes jie taikomi JS, HTML ir CSS, kur galime patikrinti, kaip EOL praleidimas turi neigiamą poveikį.

94
15 авг. Milano Adamovsky atsakymas rugpjūčio 15 d. 2014-08-15 09:31 '14 at 9:31 am 2014-08-15 09:31

Tai gali būti dėl skirtumo tarp :

  • teksto failas (kiekviena eilutė turi baigtis eilutės pabaigoje)
  • (nėra tikros „eilutės“, apie kurias kalbėti, ir failo ilgis turėtų būti išsaugotas)

Jei kiekviena eilutė baigiasi linijos pabaigoje, ji vengia, pavyzdžiui, kad dviejų tekstinių failų sujungimas paskatins pirmos eilės paskutinę eilutę antrojoje eilutėje.

Be to, redaktorius įkrovos metu gali patikrinti, ar failas baigiasi linijos pabaigoje, išsaugo jį vietinėje „eol“ parinktyje ir naudoja jį rašydamas failą.

Prieš keletą metų (2005 m.) Daugelis redaktorių (ZDE, Eclipse, Scite, ...) „pamiršo“, kad galutinis EOL, kuris nebuvo labai vertinamas .
Ne tik tai, bet jie neteisingai aiškino šį galutinį EOL, nes jie „pradėjo naują liniją“ ir iš tikrųjų pradėjo rodyti kitą eilutę, lyg ji jau egzistuotų.
Tai buvo puikiai matoma naudojant „teisingą“ tekstinį failą su gerai pasirinktu teksto redaktoriumi, pavyzdžiui, „vim“, palyginti su atidarymu viename iš pirmiau minėtų redaktorių. Jis parodė papildomą eilutę žemiau faktinės paskutinės failo eilutės. Matote kažką panašaus:

 1 first line 2 middle line 3 last line 4 
59
08 апр. Atsakymas pateikiamas VonC 08 balandžio. 2009-04-08 15:29 '09, 15:29, 2009-04-08 15:29

Kai kurie įrankiai tai tikisi. Pavyzdžiui, „ wc tikisi, kad:

 $ echo -n "Line not ending in a new line" | wc -l 0 $ echo "Line ending with a new line" | wc -l 1 
39
12 окт. Atsakymą pateikė Flimmas spalio 12 d. 2011-10-12 17:16 '11, 17:16, 2011-10-12 17:16

Iš esmės yra daug programų, kurios neteisingai apdoros failus, nebent gaus galutinį EOL EOF.

Persijos įlankos bendradarbiavimo taryba įspėja apie tai, nes tikimasi, kad ji bus C standarto dalis (žr. 5.1.1.2 skirsnį).

"Nėra naujos eilutės failo pabaigoje" kompiliatoriaus įspėjimas

18
08 апр. atsakymas pateikiamas cgp 08 apr. 2009-04-08 15:21 '09, 15:21, 2009-04-08 15:21

Tai atsitinka nuo pirmųjų paprastų terminalų naudojimo dienų. Nauja char linija buvo naudojama perduoti perduotų duomenų „iš naujo“.

Šiandien naujoji char linija nebėra reikalinga. Žinoma, daugelyje programų vis dar kyla problemų, jei nauja linija neegzistuoja, bet manau, kad šiose programose yra klaida.

Jei turite teksto failo formatą, kur reikalinga nauja linija, gausite paprastą duomenų patikrinimą labai pigiai: jei failas baigiasi linija, kurios pabaigoje nėra naujos eilutės, žinote, kad failas yra sugadintas. Su kiekviena eilute tik vienas papildomas baitas, galite aptikti sugadintus failus labai tiksliai ir beveik be procesoriaus laiko.

12
08 апр. Atsakymą pateikė Stefan 08 balandžio. 2009-04-08 15:41 '09, 15:41, 2009-04-08 15:41

Atskiras precedentas: kai tekstinį failą valdo versija (šiuo atveju, konkrečiai pagal git, nors tai taikoma ir kitiems). Jei turinys pridedamas prie failo pabaigos, tada eilutė, kuri anksčiau buvo paskutinė eilutė, bus redaguojama įtraukiant naują eilutės simbolį. Tai reiškia, kad blame failas, norėdamas sužinoti, kada ši eilutė buvo paskutinį kartą redaguota, parodys teksto pridėjimą, o ne fiksavimą iki taško, kurį tikrai norėjote pamatyti.

11
05 сент. Atsakymą pateikė Robin Whittleton 05 rugsėjis 2016-09-05 16:17 '16, 16:17 pm 2016-09-05 16:17

Be pirmiau minėtų praktinių sumetimų, nenustebčiau, jei „Unix“ kūrėjai (Thompson, Ritchie ir kt.) Ar jų pirmtakai „Multics“ suprastų, kad yra teorinė priežastis naudoti linijos terminatorius, o ne linijos ribotuvus: su linijos terminatoriais galite koduoti viską galimų eilutės failų. Naudojant linijos ribotuvus, nėra skirtumo tarp nulinės eilutės failo ir failo, turinčio vieną tuščią eilutę; abu yra koduojami kaip failai, kuriuose yra nulinių simbolių.

Taigi priežastys yra šios:

  • Kadangi ji apibrėžia POSIX.
  • Kadangi kai kurie įrankiai tikisi arba elgiasi blogai be jo. Pavyzdžiui, „ wc -l neskaito galutinės „eilutės“, nebent ji baigiasi nauja eilute.
  • Nes tai lengva ir patogi. „Unix“ cat dirba ir veikia be komplikacijų. Jis paprasčiausiai nukopijuoja kiekvieno failo baitus, nereikalaujant aiškinimo. Nemanau, kad DOS ekvivalentas yra cat . Naudojant copy a+bc , paskutinė failo a eilutė sujungiama su pirmąja b eilutės eilute.
  • Kadangi nulinės eilutės failas (arba srautas) gali būti atskiriamas nuo vieno tuščio eilutės failo.
10
25 сент. John Wiersba atsakymas 25 Sep. 2015-09-25 15:23 '15, 15:23, 2015-09-25 15:23

Taip pat kyla problemų su programavimu su failais, kuriuose nėra naujų eilučių: įmontuotas read Bash“ (aš nežinau apie kitus read ) neveikia taip, kaip tikėtasi:

 printf $'foo\nbar' | while read line do echo $line done 

Atspausdintas tik foo ! Taip yra todėl, kad kai read susiduria su paskutine eilute, jis įrašo turinį į $line , bet grąžina išėjimo kodą 1, nes jis pasiekė EOF. Tai pertraukia while , todėl niekada nepasiekiame echo $line . Jei norite tvarkyti šią situaciją, turite atlikti šiuos veiksmus:

 while read line || [ -n "${line-}" ] do echo $line done < <(printf $'foo\nbar') 

Tai reiškia, kad echo , jei read nepavyko dėl to, kad failo pabaigoje nebuvo tuščios eilutės. Žinoma, šiuo atveju produkcija bus dar viena nauja linija, kuri nebuvo įvesta.

10
04 нояб. atsakymas pateiktas l0b0 04 lapkričio. 2011-11-04 13:12 '11, 13:12, 2011-11-04 13:12

Manoma, kad paprasta, kad tam tikras analizavimo kodas turėtų tikėtis, kad jis bus.

Nesu tikras, kad manau, kad tai yra „taisyklė“, ir tai tikrai nėra tai, ką laikau religiniu požiūriu. Labiausiai pagrįstas kodas žinos, kaip apdoroti tekstą (įskaitant koduotes) (bet kokį linijos galų pasirinkimą), su nauja linija paskutinėje eilutėje arba be jos.

Tiesą sakant, jei baigsite naują eilutę: ar (teoriškai) yra tuščia galinė linija tarp EOL ir EOF? Vienas apmąstyti ...

9
08 апр. Atsakymą pateikė Marc Gravell 08 balandžio. 2009-04-08 15:19 '09, 15:19, 2009-04-08 15:19

Kodėl tekstiniai failai baigiasi nauja eilute?

Taip pat išreiškė daugelis, nes:

  • Daugelis programų neveikia gerai arba be jų.

  • Net programose, kurios tvarko failą gerai, nėra '\n' , įrankio funkcionalumas gali neatitikti vartotojų lūkesčių, kurios šiuo atveju gali būti neaiškios.

  • Programos retai draudžia galutinį '\n' (nieko nežinau).


Tačiau tai kelia klausimą:

Ką turėtų daryti kodas su tekstiniais failais be naujos eilutės?

  • Svarbiausia yra ne parašyti kodą, kuris prielaida, kad tekstinis failas baigiasi nauja eilute . Darant prielaidą, kad failas atitinka formatą, tai veda prie duomenų korupcijos, įsilaužėlių atakų ir gedimų. Pavyzdys:

     // Bad code while (fgets(buf, sizeof buf, instream)) { // What happens if there is no \n, buf[] is truncated leading to who knows what buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing \n ... } 
  • Jei reikalingas galutinis '\n' , įspėkite vartotoją apie jo nebuvimą ir veiksmus. IOW, patikrinkite failo formatą. Pastaba Tai gali apimti maksimalios eilutės ilgio, simbolių kodavimo ir kt.

  • Aiškiai nurodykite dokumentą, tvarkykite kodą, kuriame nėra galutinio '\n' .

  • Negalima sukurti failo, kuriame nėra pabaigos '\n' .

7
20 июня '15 в 18:26 2015-06-20 18:26 atsakymas pateikiamas birželio 20 d. 15 val. 18:26 2015-06-20 18:26

Aš per daug metų stebėjau. Tačiau šiandien bėgo į rimtą priežastį.

Pateikite failą su įrašu kiekvienoje eilutėje (pvz., CSV failas). Ir kad kompiuteris įrašė įrašą failo pabaigoje. Bet jis staiga sumažėjo. Ar ji buvo paskutinė eilutė? (ne gera situacija)

Bet jei mes visuomet užpildysime paskutinę eilutę, mes žinosime (tiesiog patikrinkite, ar baigta paskutinė eilutė). Priešingu atveju, mes galime kiekvieną kartą atsisakyti paskutinės eilutės, kad būtų saugus.

6
06 марта '16 в 0:53 2016-03-06 00:53 atsakymas pateikiamas simbionu kovo 06 d. 16 val. 0:53 2016-03-06 00:53

Čia labai vėlyvas, bet susidūriau su viena failų apdorojimo klaida, kuri įvyko dėl to, kad failai nesibaigė tuščiu eilutės kanalu. Mes apdorojome tekstinius failus su sed ir sed praleidžiant paskutinę išvesties eilutę, kuri sukėlė neteisingą „json“ struktūrą ir likusį procesą išsiuntė į avarijos būseną.

Viskas, ką darėme, buvo:

Yra vienas pavyzdys failas: foo.txt su tam tikru „ foo.txt turiniu.

 [{ someProp: value }, { someProp: value }] <-- No newline here 

Failas sukurtas našlės mašinoje, o >

Kai apdorojome tą patį failą, naudodami sed 's|value|newValue|g' foo.txt > foo.txt.tmp į sed 's|value|newValue|g' foo.txt > foo.txt.tmp Naujai sukurtas failas buvo

 [{ someProp: value }, { someProp: value