Projekt parasolowy Scala IO składa się z kilku podprojektów dotyczących różnych aspektów i rozszerzeń IO.
Istnieją dwa główne składniki Scala IO:
Core - Core zajmuje się głównie odczytywaniem i zapisywaniem danych do iz dowolnych źródeł i ujść. Kamień węgielny cechy są Input, Outputi Seekablektóre stanowią rdzeń API.
Inne klasy znaczenie mają Resource, ReadCharsi WriteChars.
Plik - plik jest File(nazywanym Path) interfejsem API opartym na połączeniu systemu plików Java 7 NIO i interfejsów API SBT PathFinder. Pathi FileSystemsą głównymi punktami wejścia do Scala IO File API.
import scalax.io._
val output:Output=Resource.fromFile("someFile")// Note: each write will open a new connection to file and // each write is executed at the begining of the file,// so in this case the last write will be the contents of the file.// See Seekable for append and patching files// Also See openOutput for performing several writes with a single connection
output.writeIntsAsBytes(1,2,3)
output.write("hello")(Codec.UTF8)
output.writeStrings(List("hello","world")," ")(Codec.UTF8)
Oryginalna odpowiedź (styczeń 2011), ze starym miejscem na scala-io:
{// several examples of writing dataimport scalax.io.{FileOps,Path,Codec,OpenOption}// the codec must be defined either as a parameter of ops methods or as an implicitimplicitval codec = scalax.io.Codec.UTF8
val file:FileOps=Path("file")// write bytes// By default the file write will replace// an existing file with the new data
file.write (Array(1,2,3) map ( _.toByte))// another option for write is openOptions which allows the caller// to specify in detail how the write should take place// the openOptions parameter takes a collections of OpenOptions objects// which are filesystem specific in general but the standard options// are defined in the OpenOption object// in addition to the definition common collections are also defined// WriteAppend for example is a List(Create, Append, Write)
file.write (List(1,2,3) map (_.toByte))// write a string to the file
file.write("Hello my dear file")// with all options (these are the default options explicitely declared)
file.write("Hello my dear file")(codec =Codec.UTF8)// Convert several strings to the file// same options apply as for write
file.writeStrings("It costs"::"one"::"dollar"::Nil)// Now all options
file.writeStrings("It costs"::"one"::"dollar"::Nil,
separator="||\n||")(codec =Codec.UTF8)}
Czy to naprawdę aktualna sugestia dotycząca Scali 2.10? Używać Scala IO? Nie ma jeszcze nic w rdzeniu Scala?
Phil,
2
Nigdy nie używałem scalax.io, ale sądząc po tych przykładowych wierszach, wygląda na to, że jego projekt API jest dość zły. Mieszanie metod dla danych znakowych i binarnych w jednym interfejsie nie ma sensu i najprawdopodobniej doprowadzi do błędów w kodowaniu, które są trudne do znalezienia. Projekt java.io (Reader / Writer vs. InputStream / OutputStream) wydaje się znacznie lepszy.
jcsahnwaldt Przywróć Monikę
211
Jest to jedna z funkcji brakujących w standardowej Scali, która okazała się tak przydatna, że dodaję ją do mojej osobistej biblioteki. (Prawdopodobnie powinieneś też mieć osobistą bibliotekę.) Kod wygląda tak:
def printToFile(f: java.io.File)(op: java.io.PrintWriter=>Unit){val p =new java.io.PrintWriter(f)try{ op(p)}finally{ p.close()}}
i jest używany w ten sposób:
import java.io._
val data =Array("Five","strings","in","a","file!")
printToFile(newFile("example.txt")){ p =>
data.foreach(p.println)}
new java.io.PrintWriter () używa domyślnego kodowania platformy, co prawdopodobnie oznacza, że plik wynikowy nie jest zbyt przenośny. Na przykład, jeśli chcesz utworzyć plik, który możesz później wysłać pocztą e-mail, prawdopodobnie powinieneś użyć konstruktora PrintWriter, który pozwala określić kodowanie.
jcsahnwaldt Przywróć Monikę
@JonaChristopherSahnwaldt - Jasne, w szczególnych przypadkach możesz chcieć określić kodowanie. Wartość domyślna dla platformy jest średnio najbardziej rozsądną wartością domyślną. To samo co w przypadku Source(domyślne kodowanie). Możesz oczywiście dodać np. enc: Option[String] = NoneParametr po, fjeśli uznasz to za powszechną potrzebę.
Rex Kerr,
6
@RexKerr - Nie zgadzam się. Prawie we wszystkich przypadkach należy określić kodowanie. Większość błędów kodowania, które napotykam, ma miejsce, ponieważ ludzie nie rozumieją lub nie myślą o kodowaniu. Używają wartości domyślnej i nawet o tym nie wiedzą, ponieważ zbyt wiele interfejsów API pozwala im uciec. Obecnie najbardziej rozsądnym domyślnym byłoby prawdopodobnie UTF-8. Może pracujesz tylko z językiem angielskim i innymi językami, które można zapisać w ASCII. Szczęściarz. Mieszkam w Niemczech i musiałem naprawić więcej połamanych umlautów, niż bym pamiętał.
jcsahnwaldt Przywróć Monikę
3
@JonaChristopherSahnwaldt - To jest powód, aby mieć rozsądne domyślne kodowanie, a nie zmuszać wszystkich do ciągłego określania go. Ale jeśli korzystasz z komputera Mac, a twoje pliki napisane przez Javę są gobbledygook, ponieważ nie są zakodowane w systemie Mac OS Roman, nie jestem pewien, czy przyniesie to więcej korzyści niż szkody. Myślę, że to wina platform, że nie zgodziły się na zestaw znaków. Jako indywidualny programista wpisanie łańcucha naprawdę nie rozwiąże problemu. (Wszyscy deweloperzy zgadzając się na UTF-8 będzie, ale potem, że można po prostu przejść się jako domyślne.)
Rex Kerr
@JonaChristopherSahnwaldt +10 za naprawienie wszystkich zepsutych umlautów. Nie możesz użyć młotka, może dziurkacza? A może to już dziury, które trzeba wypełnić, może ten facet może pomóc youtube.com/watch?v=E-eBBzWEpwE Ale poważnie, wpływ ASCII jest tak szkodliwy na świecie, zgadzam się, że powinien być określony i domyślnie jako UTF- 8
Davos
50
Podobna do odpowiedzi Rexa Kerra, ale bardziej ogólna. Najpierw używam funkcji pomocniczej:
/**
* Used for reading/writing to database, files, etc.
* Code From the book "Beginning Scala"
* http://www.amazon.com/Beginning-Scala-David-Pollak/dp/1430219890
*/def using[A <:{def close():Unit}, B](param: A)(f: A => B): B =try{ f(param)}finally{ param.close()}
Następnie używam tego jako:
def writeToFile(fileName:String, data:String)=
using (newFileWriter(fileName)){
fileWriter => fileWriter.write(data)}
i
def appendToFile(fileName:String, textData:String)=
using (newFileWriter(fileName,true)){
fileWriter => using (newPrintWriter(fileWriter)){
printWriter => printWriter.println(textData)}}
Nie zrozum mnie źle, podoba mi się Twój kod i jest bardzo pouczający, ale im więcej widzę takie konstrukcje dla prostych problemów, tym bardziej przypomina mi on stary żart z „hello world”: ariel.com.au/jokes/The_Evolution_of_a_Programmer .html :-) (+1 głos ode mnie).
greenoldman
4
Jeśli piszesz jednolinijki, nic się nie liczy. Jeśli piszesz znaczące programy (duże z ciągłą potrzebą konserwacji i ewolucji), tego rodzaju myślenie prowadzi do najszybszego i najbardziej zgubnego rodzaju degradacji jakości oprogramowania.
Randall Schulz
3
Nie każdy będzie miał „oczy łuskowate” aż do pewnego poziomu praktyki - zabawne jest widzieć, że ten przykład kodu pochodzi ze „Początkowej” Scali
asyncwait
asyncwait "początek" scala ... najbardziej ironiczny tytuł wszechczasów, uwaga: mam książkę ... i dopiero teraz zaczynam ją rozumieć .. Przypuszczam, że byłem o krok przed "początkującym" lol: D ........
user1050817
1
Problem polega mniej na sztuczkach Scali, ale w gadatliwości i kiepskim stylu. Zredagowałem to, aby było bardziej czytelne. Po moim refaktorze to tylko 4 linie (dobrze, 4 z długością linii IDE, użyte tutaj 6, aby zmieścić się na ekranie). IMHO to teraz bardzo fajna odpowiedź.
@samthebest czy mógłbyś dodać biblioteki, importz których korzystasz?
Daniel,
1
Od wersji java 7 użyj zamiast tego java.nio.file: def writeToFile (file: String, stringToWrite: String): Unit = {val writer = Files.newBufferedWriter (Paths.get (file)) try writer.write (stringToWrite) w końcu writer.close ()}
E Shindler
20
Udzielenie innej odpowiedzi, ponieważ moje zmiany innych odpowiedzi zostały odrzucone.
To najbardziej zwięzła i prosta odpowiedź (podobna do odpowiedzi Garret Hall)
File("filename").writeAll("hello world")
Jest to podobne do Jus12, ale bez gadatliwości i z poprawnym stylem kodu
def using[A <:{def close():Unit}, B](resource: A)(f: A => B): B =try f(resource)finally resource.close()def writeToFile(path:String, data:String):Unit=
using(newFileWriter(path))(_.write(data))def appendToFile(path:String, data:String):Unit=
using(newPrintWriter(newFileWriter(path,true)))(_.println(data))
Zauważ, że NIE potrzebujesz nawiasów klamrowych dla try finallyani lambd i zwróć uwagę na użycie składni zastępczej. Zwróć także uwagę na lepsze nazewnictwo.
Przepraszamy, ale twój kod jest możliwy do wyobrażenia, nie spełnia on implementedwarunku wstępnego. Nie możesz użyć kodu, który nie został zaimplementowany. Chodzi mi o to, że musisz powiedzieć, jak go znaleźć, ponieważ nie jest on domyślnie dostępny i nie jest dobrze znany.
Val
15
Oto zwięzły, jednowierszowy tekst wykorzystujący bibliotekę kompilatora Scala:
Dlaczego nie jest to odpowiednie dla dużych plików?
Chetan Bhasin,
2
@ChetanBhasin Prawdopodobnie dlatego, writeże skopiuje contentsdo nowej tablicy bajtów zamiast przesyłać ją strumieniowo do pliku, przez co w szczytowym momencie zużyje dwa razy więcej pamięci niż contentssam.
Daniel Werner
10
Niestety dla najlepszej odpowiedzi, Scala-IO nie żyje. Jeśli nie masz nic przeciwko korzystaniu z zależności od innej firmy, rozważ użycie mojej biblioteki OS-Lib . To sprawia, że praca z plikami, ścieżkami i systemem plików jest bardzo łatwa:
// Make sure working directory exists and is emptyval wd = os.pwd/"out"/"splash"
os.remove.all(wd)
os.makeDir.all(wd)// Read/write files
os.write(wd/"file.txt","hello")
os.read(wd/"file.txt")==>"hello"// Perform filesystem operations
os.copy(wd/"file.txt", wd/"copied.txt")
os.list(wd)==>Seq(wd/"copied.txt", wd/"file.txt")
Również tutaj - to pytanie jest jednym z największych hitów podczas wyszukiwania w Google, jak napisać plik za pomocą scali - teraz, gdy Twój projekt urósł, możesz nieco rozszerzyć swoją odpowiedź?
asac
6
Począwszy Scala 2.13od biblioteki standardowej dostępne jest dedykowane narzędzie do zarządzania zasobami:Using .
Można go użyć w tym przypadku z zasobami takimi jak PrintWriterlub BufferedWriterktóre rozszerzają się AutoCloseable, aby zapisać do pliku i, bez względu na wszystko, później zamknąć zasób:
Począwszy od Scala 2.13, preferuj używanie scala.util
Naprawiono błąd polegający na tym, finallyże połknął oryginał Exceptionrzucony przez, tryjeśli finallykod wyrzucił plikException
Po przejrzeniu wszystkich tych odpowiedzi, jak łatwo napisać plik w Scali, a niektóre z nich są całkiem fajne, miałem trzy problemy:
W odpowiedzi Jus12 , użycie curry do metody pomocniczej jest nieoczywiste dla początkujących Scala / FP
Musi hermetyzować błędy niższego poziomu za pomocą scala.util.Try
Musi pokazać programistom Java, którzy nie znają Scala / FP, jak prawidłowo zagnieżdżać zasoby zależne, aby closemetoda była wykonywana na każdym zasobie zależnym w odwrotnej kolejności - Uwaga: zamykanie zasobów zależnych w odwrotnej kolejności, SZCZEGÓLNIE W PRZYPADKU AWARII jest rzadko rozumianym wymogiem java.lang.AutoCloseablespecyfikacja, która często prowadzi do bardzo złośliwa i trudno znaleźć błędy i awarie w czasie run
Przed rozpoczęciem moim celem nie jest zwięzłość. Ma to na celu ułatwienie zrozumienia dla początkujących użytkowników Scala / FP, zazwyczaj tych pochodzących z języka Java. Na samym końcu połączę wszystkie bity razem, a następnie zwiększę zwięzłość.
Po pierwsze, usingmetoda musi zostać zaktualizowana, aby mogła być używana Try(ponownie, zwięzłość nie jest tutaj celem). Nazwa zostanie zmieniona na tryUsingAutoCloseable:
def tryUsingAutoCloseable[A <:AutoCloseable, R](instantiateAutoCloseable:()=> A)//parameter list 1(transfer: A => scala.util.Try[R])//parameter list 2: scala.util.Try[R]=Try(instantiateAutoCloseable()).flatMap(
autoCloseable =>{var optionExceptionTry:Option[Exception]=Nonetry
transfer(autoCloseable)catch{case exceptionTry:Exception=>
optionExceptionTry =Some(exceptionTry)throw exceptionTry
}finallytry
autoCloseable.close()catch{case exceptionFinally:Exception=>
optionExceptionTry match{caseSome(exceptionTry)=>
exceptionTry.addSuppressed(exceptionFinally)caseNone=>throw exceptionFinally
}}})
Początek powyższej tryUsingAutoCloseablemetody może być mylący, ponieważ wydaje się, że ma dwie listy parametrów zamiast zwyczajowej listy pojedynczych parametrów. Nazywa się to curry. I nie będę szczegółowo omawiać, jak działa curry ani gdzie występuje sporadycznie przydatne. Okazuje się, że dla tej konkretnej przestrzeni problemowej jest to odpowiednie narzędzie do pracy.
Następnie musimy stworzyć metodę, tryPrintToFilektóra utworzy (lub nadpisze istniejącą) Filei zapisze List[String]. Używa, FileWriterktóry jest zamknięty przez a, BufferedWriterktóry z kolei jest zamknięty w PrintWriter. Aby podnieść wydajność, BufferedWriterzdefiniowano domyślny rozmiar buforu znacznie większy niż domyślny dla ,defaultBufferSize i przypisano wartość 65536.
Oto kod (i znowu zwięzłość nie jest tutaj celem):
val defaultBufferSize:Int=65536def tryPrintToFile(
lines:List[String],
location: java.io.File,
bufferSize:Int= defaultBufferSize
): scala.util.Try[Unit]={
tryUsingAutoCloseable(()=>new java.io.FileWriter(location)){//this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
fileWriter =>
tryUsingAutoCloseable(()=>new java.io.BufferedWriter(fileWriter, bufferSize)){//this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
bufferedWriter =>
tryUsingAutoCloseable(()=>new java.io.PrintWriter(bufferedWriter)){//this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
printWriter =>
scala.util.Try(
lines.foreach(line => printWriter.println(line)))}}}}
Powyższa tryPrintToFilemetoda jest przydatna, ponieważ wymaga plikuList[String] dane wejściowe i wysyła je do pliku File. Utwórzmy teraz tryWriteToFilemetodę, która pobiera a Stringi zapisuje ją w pliku File.
Oto kod (i pozwolę ci odgadnąć priorytet zwięzłości tutaj):
def tryWriteToFile(
content:String,
location: java.io.File,
bufferSize:Int= defaultBufferSize
): scala.util.Try[Unit]={
tryUsingAutoCloseable(()=>new java.io.FileWriter(location)){//this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
fileWriter =>
tryUsingAutoCloseable(()=>new java.io.BufferedWriter(fileWriter, bufferSize)){//this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
bufferedWriter =>Try(bufferedWriter.write(content))}}}
Na koniec warto mieć możliwość pobrania zawartości pliku Filejako pliku String. Chociaż scala.io.Sourcezapewnia wygodną metodę łatwego uzyskiwania zawartości pliku File, closemetoda ta musi być używana w Sourcecelu zwolnienia podstawowej maszyny JVM i uchwytów systemu plików. Jeśli tak się nie stanie, zasób nie zostanie zwolniony, dopóki JVM GC (moduł wyrzucania elementów bezużytecznych) nie wydaSource samej instancji. Nawet wtedy istnieje tylko słaba JVM gwarancja, że finalizemetoda zostanie wywołana przez GC do closezasobu. Oznacza to, że obowiązkiem klienta jest jawne wywołanie pliku . W tym celu potrzebujemy drugiej definicji metody using, która obsługuje .close metody, tak samo jak klient jest odpowiedzialny za oparcie się closena wystąpieniujava.lang.AutoCloseablescala.io.Source
A oto przykład jego użycia w super prostym czytniku plików strumieniowych (obecnie używany do odczytu plików rozdzielanych tabulatorami z danych wyjściowych bazy danych):
def tryProcessSource(
file: java.io.File, parseLine:(String,Int)=>List[String]=(line, index)=>List(line), filterLine:(List[String],Int)=>Boolean=(values, index)=>true, retainValues:(List[String],Int)=>List[String]=(values, index)=> values
, isFirstLineNotHeader:Boolean=false): scala.util.Try[List[List[String]]]=
tryUsingSource(scala.io.Source.fromFile(file)){
source =>
scala.util.Try((for{(line, index)<-
source.getLines().buffered.zipWithIndex
values =
parseLine(line, index)if(index ==0&&!isFirstLineNotHeader)|| filterLine(values, index)
retainedValues =
retainValues(values, index)}yield retainedValues
).toList //must explicitly use toList due to the source.close which will//occur immediately following execution of this anonymous function))
Teraz, łącząc to wszystko razem z wyodrębnionymi importami (co znacznie ułatwia wklejenie do arkusza Scala obecnego zarówno we wtyczce Eclipse ScalaIDE, jak i IntelliJ Scala, aby ułatwić zrzucanie danych wyjściowych na pulpit, aby można je było łatwiej zbadać za pomocą edytora tekstu), tak wygląda kod (ze zwiększoną zwięzłością):
Jako nowicjusz w Scala / FP spędziłem wiele godzin (głównie w frustracji drapiącej głowę), zdobywając powyższą wiedzę i rozwiązania. Mam nadzieję, że pomoże to innym nowicjuszom w Scala / FP szybciej uporać się z tym garbem uczenia się.
Niesamowita aktualizacja. Jedynym problemem jest to, że teraz masz około 100 linii kodu, które można zastąpić try-catch-finally. Wciąż kochaj swoją pasję.
Observer
1
@Observer Chciałbym stwierdzić, że jest to niedokładne stwierdzenie. Opisywany przeze mnie wzorzec w rzeczywistości ogranicza liczbę gotowych schematów, które klient musi napisać, aby zapewnić prawidłową obsługę zamykania AutoCloseables, jednocześnie umożliwiając korzystanie ze schematu Scala idiomatic FP za pomocą scala.util.Try. Jeśli spróbujesz osiągnąć te same efekty, które mam, ręcznie wypisując bloki try / catch / final, myślę, że w końcu uzyskasz znacznie więcej schematów, niż sobie wyobrażasz. Tak więc, istnieje znacząca wartość czytelności we wpychaniu wszystkich schematów do 100 wierszy funkcji Scala.
chaotic3quilibrium
1
Przepraszam, jeśli brzmiało to w jakikolwiek sposób obraźliwe. Chodzi mi jednak o to, że nie ma takiej potrzeby w takiej ilości kodu, ponieważ to samo można by osiągnąć poprzez niefunkcjonalne podejście ze znacznie większą prostotą. Osobiście napisałbym próbę - wreszcie z dodatkowymi kontrolami. Jest po prostu krótszy. Gdybym chciał używać wrapperów, ApacheUtils są po to, aby wykorzystać całą brudną robotę. Co więcej, wszystkie standardowe czytniki / pisarze zamykają podstawowe strumienie, więc wielowarstwowe opakowanie nie jest potrzebne. PS: Zmieniłem swój głos z minus jeden na plus jeden, aby wesprzeć twoje wysiłki. Więc proszę, nie podejrzewaj mnie w złych intencjach.
Observer
Bez obrazy.
chaotic3quilibrium
1
Rozumiem twój punkt widzenia. Dzięki za dyskusję, muszę się trochę nad tym zastanowić. Miłego dnia!
Obserwator,
3
Oto przykład zapisu niektórych wierszy do pliku przy użyciu scalaz-stream .
import scalaz._
import scalaz.stream._
def writeLinesToFile(lines:Seq[String], file:String):Task[Unit]=Process(lines: _*)// Process that enumerates the lines.flatMap(Process(_,"\n"))// Add a newline after each line.pipe(text.utf8Encode)// Encode as UTF-8.to(io.fileChunkW(fileName))// Buffered write to the file.runLog[Task,Unit]// Get this computation as a Task.map(_ =>())// Discard the result
writeLinesToFile(Seq("one","two"),"file.txt").run
def write(destinationFile:Path, fileContent:String):Either[Exception,Path]=
write(destinationFile, fileContent.getBytes(StandardCharsets.UTF_8))def write(destinationFile:Path, fileContent:Array[Byte]):Either[Exception,Path]=try{Files.createDirectories(destinationFile.getParent)// Return the path to the destinationFile if the write is successfulRight(Files.write(destinationFile, fileContent))}catch{case exception:Exception=>Left(exception)}
Stosowanie
val filePath =Paths.get("./testDir/file.txt")
write(filePath ,"A test")match{caseRight(pathToWrittenFile)=> println(s"Successfully wrote to $pathToWrittenFile")caseLeft(exception)=> println(s"Could not write to $filePath. Exception: $exception")}
Podsumowanie - Java NIO (lub NIO.2 dla asynchronii) jest nadal najbardziej wszechstronnym rozwiązaniem do przetwarzania plików obsługiwanym w Scali. Poniższy kod tworzy i zapisuje tekst w nowym pliku:
import java.io.{BufferedOutputStream,OutputStream}import java.nio.file.{Files,Paths}val testFile1 =Paths.get("yourNewFile.txt")val s1 ="text to insert in file".getBytes()val out1:OutputStream=newBufferedOutputStream(Files.newOutputStream(testFile1))try{
out1.write(s1,0, s1.length)}catch{case _ => println("Exception thrown during file writing")}finally{
out1.close()}
Importuj biblioteki Java: IO i NIO
Utwórz Pathobiekt o wybranej nazwie pliku
Przekonwertuj tekst, który chcesz wstawić do pliku, na tablicę bajtów
Pobierz plik jako strumień: OutputStream
Przekaż swoją tablicę bajtów do writefunkcji strumienia wyjściowego
Odpowiedzi:
Edytuj 2019 (8 lat później), Scala-IO nie jest zbyt aktywna, jeśli w ogóle, Li Haoyi sugeruje własną bibliotekę
lihaoyi/os-lib
, którą przedstawia poniżej .Czerwiec 2019, Xavier Guihot wspomina w swojej odpowiedzi o bibliotece
Using
narzędzie do automatycznego zarządzania zasobami.Edycja (wrzesień 2011): odkąd Eduardo Costa pyta o Scala2.9 i od kiedy Rick-777 komentuje, że historia zmian scalax.IO praktycznie nie istnieje od połowy 2009 roku ...
Scala-IO zmieniło miejsce: zobacz repozytorium GitHub od Jesse Eichara (również na SO ):
Oryginalna odpowiedź (styczeń 2011), ze starym miejscem na scala-io:
Jeśli nie chcesz czekać na Scala2.9, możesz skorzystać z biblioteki scala-incubator / scala-io .
(jak wspomniano w sekcji „ Dlaczego Scala Source nie zamyka bazowego InputStream? ”)
Zobacz próbki
źródło
Jest to jedna z funkcji brakujących w standardowej Scali, która okazała się tak przydatna, że dodaję ją do mojej osobistej biblioteki. (Prawdopodobnie powinieneś też mieć osobistą bibliotekę.) Kod wygląda tak:
i jest używany w ten sposób:
źródło
Source
(domyślne kodowanie). Możesz oczywiście dodać np.enc: Option[String] = None
Parametr po,f
jeśli uznasz to za powszechną potrzebę.Podobna do odpowiedzi Rexa Kerra, ale bardziej ogólna. Najpierw używam funkcji pomocniczej:
Następnie używam tego jako:
i
itp.
źródło
Prosta odpowiedź:
źródło
import
z których korzystasz?Udzielenie innej odpowiedzi, ponieważ moje zmiany innych odpowiedzi zostały odrzucone.
To najbardziej zwięzła i prosta odpowiedź (podobna do odpowiedzi Garret Hall)
Jest to podobne do Jus12, ale bez gadatliwości i z poprawnym stylem kodu
Zauważ, że NIE potrzebujesz nawiasów klamrowych dla
try finally
ani lambd i zwróć uwagę na użycie składni zastępczej. Zwróć także uwagę na lepsze nazewnictwo.źródło
implemented
warunku wstępnego. Nie możesz użyć kodu, który nie został zaimplementowany. Chodzi mi o to, że musisz powiedzieć, jak go znaleźć, ponieważ nie jest on domyślnie dostępny i nie jest dobrze znany.Oto zwięzły, jednowierszowy tekst wykorzystujący bibliotekę kompilatora Scala:
Alternatywnie, jeśli chcesz użyć bibliotek Java, możesz to zrobić:
źródło
scala.tools.nsc.io.File("/tmp/myFile.txt")
działa w Scali 2.11.8.Jedna wkładka do zapisywania / odczytu do / z
String
, za pomocąjava.nio
.To nie jest odpowiednie dla dużych plików, ale wystarczy.
Niektóre linki:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
źródło
write
że skopiujecontents
do nowej tablicy bajtów zamiast przesyłać ją strumieniowo do pliku, przez co w szczytowym momencie zużyje dwa razy więcej pamięci niżcontents
sam.Niestety dla najlepszej odpowiedzi, Scala-IO nie żyje. Jeśli nie masz nic przeciwko korzystaniu z zależności od innej firmy, rozważ użycie mojej biblioteki OS-Lib . To sprawia, że praca z plikami, ścieżkami i systemem plików jest bardzo łatwa:
Ma jednowierszowe do zapisywania do plików , dołączania do plików , nadpisywania plików i wielu innych użytecznych / typowych operacji
źródło
Mikro biblioteka, którą napisałem: https://github.com/pathikrit/better-files
lub
źródło
Począwszy
Scala 2.13
od biblioteki standardowej dostępne jest dedykowane narzędzie do zarządzania zasobami:Using
.Można go użyć w tym przypadku z zasobami takimi jak
PrintWriter
lubBufferedWriter
które rozszerzają sięAutoCloseable
, aby zapisać do pliku i, bez względu na wszystko, później zamknąć zasób:Na przykład w przypadku
java.io
interfejsu API:Lub z
java.nio
API:źródło
AKTUALIZACJA w dniu 2019 / wrzesień / 01:
finally
że połknął oryginałException
rzucony przez,try
jeślifinally
kod wyrzucił plikException
Po przejrzeniu wszystkich tych odpowiedzi, jak łatwo napisać plik w Scali, a niektóre z nich są całkiem fajne, miałem trzy problemy:
scala.util.Try
close
metoda była wykonywana na każdym zasobie zależnym w odwrotnej kolejności - Uwaga: zamykanie zasobów zależnych w odwrotnej kolejności, SZCZEGÓLNIE W PRZYPADKU AWARII jest rzadko rozumianym wymogiemjava.lang.AutoCloseable
specyfikacja, która często prowadzi do bardzo złośliwa i trudno znaleźć błędy i awarie w czasie runPrzed rozpoczęciem moim celem nie jest zwięzłość. Ma to na celu ułatwienie zrozumienia dla początkujących użytkowników Scala / FP, zazwyczaj tych pochodzących z języka Java. Na samym końcu połączę wszystkie bity razem, a następnie zwiększę zwięzłość.
Po pierwsze,
using
metoda musi zostać zaktualizowana, aby mogła być używanaTry
(ponownie, zwięzłość nie jest tutaj celem). Nazwa zostanie zmieniona natryUsingAutoCloseable
:Początek powyższej
tryUsingAutoCloseable
metody może być mylący, ponieważ wydaje się, że ma dwie listy parametrów zamiast zwyczajowej listy pojedynczych parametrów. Nazywa się to curry. I nie będę szczegółowo omawiać, jak działa curry ani gdzie występuje sporadycznie przydatne. Okazuje się, że dla tej konkretnej przestrzeni problemowej jest to odpowiednie narzędzie do pracy.Następnie musimy stworzyć metodę,
tryPrintToFile
która utworzy (lub nadpisze istniejącą)File
i zapiszeList[String]
. Używa,FileWriter
który jest zamknięty przez a,BufferedWriter
który z kolei jest zamknięty wPrintWriter
. Aby podnieść wydajność,BufferedWriter
zdefiniowano domyślny rozmiar buforu znacznie większy niż domyślny dla ,defaultBufferSize
i przypisano wartość 65536.Oto kod (i znowu zwięzłość nie jest tutaj celem):
Powyższa
tryPrintToFile
metoda jest przydatna, ponieważ wymaga plikuList[String]
dane wejściowe i wysyła je do plikuFile
. Utwórzmy teraztryWriteToFile
metodę, która pobiera aString
i zapisuje ją w plikuFile
.Oto kod (i pozwolę ci odgadnąć priorytet zwięzłości tutaj):
Na koniec warto mieć możliwość pobrania zawartości pliku
File
jako plikuString
. Chociażscala.io.Source
zapewnia wygodną metodę łatwego uzyskiwania zawartości plikuFile
,close
metoda ta musi być używana wSource
celu zwolnienia podstawowej maszyny JVM i uchwytów systemu plików. Jeśli tak się nie stanie, zasób nie zostanie zwolniony, dopóki JVM GC (moduł wyrzucania elementów bezużytecznych) nie wydaSource
samej instancji. Nawet wtedy istnieje tylko słaba JVM gwarancja, żefinalize
metoda zostanie wywołana przez GC doclose
zasobu. Oznacza to, że obowiązkiem klienta jest jawne wywołanie pliku . W tym celu potrzebujemy drugiej definicji metody using, która obsługuje .close
metody, tak samo jak klient jest odpowiedzialny za oparcie sięclose
na wystąpieniujava.lang.AutoCloseable
scala.io.Source
Oto kod do tego (nadal nie jest zwięzły):
A oto przykład jego użycia w super prostym czytniku plików strumieniowych (obecnie używany do odczytu plików rozdzielanych tabulatorami z danych wyjściowych bazy danych):
Zaktualizowana wersja powyższej funkcji został dostarczony jako odpowiedź na inny, ale powiązanego StackOverflow pytanie .
Teraz, łącząc to wszystko razem z wyodrębnionymi importami (co znacznie ułatwia wklejenie do arkusza Scala obecnego zarówno we wtyczce Eclipse ScalaIDE, jak i IntelliJ Scala, aby ułatwić zrzucanie danych wyjściowych na pulpit, aby można je było łatwiej zbadać za pomocą edytora tekstu), tak wygląda kod (ze zwiększoną zwięzłością):
Jako nowicjusz w Scala / FP spędziłem wiele godzin (głównie w frustracji drapiącej głowę), zdobywając powyższą wiedzę i rozwiązania. Mam nadzieję, że pomoże to innym nowicjuszom w Scala / FP szybciej uporać się z tym garbem uczenia się.
źródło
try-catch-finally
. Wciąż kochaj swoją pasję.Oto przykład zapisu niektórych wierszy do pliku przy użyciu scalaz-stream .
źródło
Aby przewyższyć samthebest i współpracowników przed nim, poprawiłem nazewnictwo i zwięzłość:
źródło
Brak zależności, obsługa błędów
Either
do obsługi błędówKod
Stosowanie
źródło
Aktualizacja 2019:
Podsumowanie - Java NIO (lub NIO.2 dla asynchronii) jest nadal najbardziej wszechstronnym rozwiązaniem do przetwarzania plików obsługiwanym w Scali. Poniższy kod tworzy i zapisuje tekst w nowym pliku:
Path
obiekt o wybranej nazwie plikuOutputStream
write
funkcji strumienia wyjściowegoźródło
Podobnie jak w tej odpowiedzi , oto przykład z
fs2
(wersja 1.0.4):źródło
Ta linia pomaga napisać plik z tablicy lub łańcucha.
źródło
Jeśli mimo wszystko masz w swoim projekcie strumienie Akka, zapewnia on jednowierszowy:
Akka docs> Przesyłanie strumieniowe pliku IO
źródło