Das Scala IO-Dachprojekt besteht aus einigen Teilprojekten für verschiedene Aspekte und Erweiterungen von IO.
Es gibt zwei Hauptkomponenten von Scala IO:
Core - Core befasst sich hauptsächlich mit dem Lesen und Schreiben von Daten zu und von beliebigen Quellen und Senken. Die Eckpfeiler sind Input, Outputund Seekabledie die Kern-API bereitstellen.
Andere Klassen von Bedeutung sind Resource, ReadCharsund WriteChars.
Datei - Datei ist eine File(aufgerufene Path) API, die auf einer Kombination aus Java 7 NIO-Dateisystem und SBT PathFinder-APIs basiert. Pathund FileSystemsind die wichtigsten Einstiegspunkte in die 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)
Ursprüngliche Antwort (Januar 2011) mit dem alten Ort für 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)}
Das Scalax-Projekt scheint tot zu sein (keine Commits seit Juni 2009). Ist das richtig? Scalax Commit-Geschichte
Rick-777
@Eduardo: Ich habe meine Antwort mit dem neuen Platz für die Scala-Io-Bibliothek abgeschlossen (der für Scala2.9 aktualisiert wurde: github.com/jesseeichar/scala-io/issues/20 )
VonC
10
Ist das wirklich der aktuelle Vorschlag für Scala 2.10? Scala IO verwenden? Es gibt noch nichts in der Kern-Scala?
Phil
2
Ich habe scalax.io noch nie verwendet, aber nach diesen Beispielzeilen zu urteilen, scheint das API-Design ziemlich schlecht zu sein. Das Mischen von Methoden für Zeichen- und Binärdaten in einer Schnittstelle ist wenig sinnvoll und führt sehr wahrscheinlich zu schwer zu findenden Codierungsfehlern. Das Design von java.io (Reader / Writer vs. InputStream / OutputStream) scheint viel besser zu sein.
jcsahnwaldt Reinstate Monica
211
Dies ist eine der Funktionen, die in der Standard-Scala fehlen und die ich so nützlich fand, dass ich sie meiner persönlichen Bibliothek hinzufüge. (Sie sollten wahrscheinlich auch eine persönliche Bibliothek haben.) Der Code sieht folgendermaßen aus:
def printToFile(f: java.io.File)(op: java.io.PrintWriter=>Unit){val p =new java.io.PrintWriter(f)try{ op(p)}finally{ p.close()}}
und es wird so verwendet:
import java.io._
val data =Array("Five","strings","in","a","file!")
printToFile(newFile("example.txt")){ p =>
data.foreach(p.println)}
new java.io.PrintWriter () verwendet die Standardcodierung der Plattform, was wahrscheinlich bedeutet, dass die Ergebnisdatei nicht sehr portabel ist. Wenn Sie beispielsweise eine Datei erstellen möchten, die Sie später per E-Mail versenden können, sollten Sie wahrscheinlich den PrintWriter-Konstruktor verwenden, mit dem Sie eine Codierung angeben können.
jcsahnwaldt Reinstate Monica
@JonaChristopherSahnwaldt - Sicher, in besonderen Fällen möchten Sie möglicherweise die Codierung angeben. Die Standardeinstellung für die Plattform ist im Durchschnitt die sinnvollste Standardeinstellung. Gleich wie bei Source(Standardcodierung standardmäßig). Sie können natürlich zB einen enc: Option[String] = NoneParameter nach hinzufügen, fwenn Sie dies als häufigen Bedarf empfinden.
Rex Kerr
6
@ RexKerr - Ich bin anderer Meinung. In fast allen Fällen sollte die Kodierung angegeben werden. Die meisten Codierungsfehler treten auf, weil die Leute die Codierung nicht verstehen oder nicht darüber nachdenken. Sie verwenden die Standardeinstellung und wissen es nicht einmal, weil zu viele APIs sie damit davonkommen lassen. Heutzutage wäre UTF-8 wahrscheinlich der sinnvollste Standard. Vielleicht arbeiten Sie nur mit Englisch und anderen Sprachen, die in ASCII geschrieben werden können. Du Glückspilz. Ich lebe in Deutschland und musste mehr kaputte Umlaute reparieren, als ich mir merken möchte.
jcsahnwaldt Reinstate Monica
3
@JonaChristopherSahnwaldt - Dies ist ein Grund für eine sinnvolle Standardcodierung, nicht um jeden zu zwingen, sie ständig anzugeben. Aber wenn Sie auf einem Mac arbeiten und Ihre von Java geschriebenen Dateien gobbledygook sind, weil sie nicht mit Mac OS Roman codiert sind, bin ich mir nicht sicher, ob es mehr nützt als schadet. Ich denke, es ist die Schuld der Plattformen, dass sie sich nicht auf einen Zeichensatz geeinigt haben. Als einzelner Entwickler wird das Problem durch Eingabe eines Strings nicht wirklich gelöst. (Alle Entwickler, die sich auf UTF-8 einigen, würden dies tun, aber dann kann dies standardmäßig aktiviert werden.)
Rex Kerr
@JonaChristopherSahnwaldt +10 zum Reparieren des kaputten Umlauts. Kannst du keinen Hammer benutzen, vielleicht einen Locher? Oder sind es bereits Löcher, die gefüllt werden müssen? Vielleicht kann dieser Typ youtube.com/watch?v=E-eBBzWEpwE helfen. Aber im Ernst, der Einfluss von ASCII ist in der Welt so schädlich. 8
Davos
50
Ähnlich der Antwort von Rex Kerr, aber allgemeiner. Zuerst benutze ich eine Hilfsfunktion:
/**
* 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()}
Dann benutze ich dies als:
def writeToFile(fileName:String, data:String)=
using (newFileWriter(fileName)){
fileWriter => fileWriter.write(data)}
und
def appendToFile(fileName:String, textData:String)=
using (newFileWriter(fileName,true)){
fileWriter => using (newPrintWriter(fileWriter)){
printWriter => printWriter.println(textData)}}
Versteh mich nicht falsch, ich mag deinen Code und er ist sehr lehrreich, aber je mehr ich solche Konstrukte für einfache Probleme sehe, desto mehr erinnert er mich an den alten "Hallo Welt" -Witz: ariel.com.au/jokes/The_Evolution_of_a_Programmer .html :-) (+1 Stimme von mir).
Greenoldman
4
Wenn Sie Einzeiler schreiben, ist überhaupt nichts wichtig. Wenn Sie wichtige Programme schreiben (groß mit ständigem Wartungs- und Entwicklungsbedarf), führt diese Art des Denkens zu der schnellsten und schädlichsten Art der Verschlechterung der Softwarequalität.
Randall Schulz
3
Nicht jeder wird "Scala-Augen" haben, bis ein gewisses Maß an Übung erreicht ist - es ist lustig zu sehen, dass dieses Codebeispiel von "Beginning" Scala stammt
asyncwait
asyncwait "begin" scala ... der ironischste Titel aller Zeiten, Anmerkung: Ich habe das Buch ... und gerade jetzt fange ich an, es zu verstehen ... Ich nehme an, als ich ein Schritt vor "Anfänger" war lol: D. ........
user1050817
1
Das Problem sind weniger die Scala-Tricks hier, sondern die Ausführlichkeit und der schlechte Stil. Ich habe dies viel besser lesbar bearbeitet. Nach meinem Refactor sind es nur 4 Zeilen (nun, 4 mit IDE-Zeilenlängen, hier werden 6 verwendet, um in den Bildschirm zu passen). IMHO ist es jetzt sehr schöne Antwort.
@samthebest könnten Sie die Bibliotheken hinzufügen, importaus denen Sie ?
Daniel
1
Verwenden Sie ab Java 7 stattdessen java.nio.file: def writeToFile (Datei: String, stringToWrite: String): Unit = {val writer = Files.newBufferedWriter (Paths.get (Datei)) Versuchen Sie schließlich writer.write (stringToWrite) writer.close ()}
E Shindler
20
Eine andere Antwort geben, weil meine Änderungen anderer Antworten abgelehnt wurden.
Dies ist die prägnanteste und einfachste Antwort (ähnlich wie bei Garret Hall).
File("filename").writeAll("hello world")
Dies ist vergleichbar mit Jus12, aber ohne die Ausführlichkeit und mit dem richtigen Code - Stil
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))
Beachten Sie try finally, dass Sie weder die geschweiften Klammern noch Lambdas benötigen , und beachten Sie die Verwendung der Platzhaltersyntax. Beachten Sie auch eine bessere Benennung.
Entschuldigung, aber Ihr Code ist vorstellbar, er erfüllt nicht die implementedVoraussetzung. Sie können den nicht implementierten Code nicht verwenden. Ich meine, Sie müssen sagen, wie Sie es finden, da es standardmäßig nicht verfügbar und nicht bekannt ist.
Val
15
Hier ist ein prägnanter Einzeiler, der die Scala-Compiler-Bibliothek verwendet:
@ChetanBhasin Wahrscheinlich, weil in ein neues Byte-Array writekopiert wird contents, anstatt es in die Datei zu streamen, wodurch auf seinem Höhepunkt doppelt so viel Speicher verbraucht wird als contentsallein.
Daniel Werner
10
Unglücklicherweise für die Top-Antwort ist Scala-IO tot. Wenn es Ihnen nichts ausmacht, eine Abhängigkeit von Drittanbietern zu verwenden, sollten Sie meine OS-Lib-Bibliothek verwenden . Dies macht die Arbeit mit Dateien, Pfaden und dem Dateisystem sehr einfach:
// 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")
Auch hier - Diese Frage ist einer der Top-Hits beim Googeln, wie man eine Datei mit Scala schreibt - jetzt, wo Ihr Projekt größer geworden ist, möchten Sie vielleicht Ihre Antwort ein wenig erweitern?
Asac
6
Ab Scala 2.13dem Start bietet die Standardbibliothek ein dediziertes Dienstprogramm zur Ressourcenverwaltung : Using.
Es kann in diesem Fall mit Ressourcen wie PrintWriteroder verwendet werden, BufferedWriterdie erweitert AutoCloseablewerden, um in eine Datei zu schreiben und die Ressource anschließend zu schließen, egal was passiert:
Fehler finallybehoben Exception, durch den das Original verschluckt wurde , trywenn der finallyCode einException
Nachdem ich all diese Antworten zum einfachen Schreiben einer Datei in Scala überprüft hatte und einige davon sehr nett sind, hatte ich drei Probleme:
In der Antwort des Jus12 ist die Verwendung von Currying für die Verwendung der Hilfsmethode für Scala / FP-Anfänger nicht offensichtlich
Muss Fehler niedrigerer Ebene mit kapseln scala.util.Try
Bedürfnisse zu zeigen , Java - Entwickler neue Scala / FP , wie man richtig Nest abhängige Ressourcen , so dass die closeMethode auf jede abhängige Ressource in umgekehrten Reihenfolge - Hinweis: Schließen abhängige Ressourcen in umgekehrter Reihenfolge vor allem im Fall eines Fehlers ist ein selten verstanden Erfordernis Die java.lang.AutoCloseableSpezifikation, die dazu neigt, zu sehr schädlichen und schwer zu findenden Fehlern und Laufzeitfehlern zu führen
Bevor ich anfange, ist mein Ziel nicht prägnant. Dies soll Scala / FP-Anfängern, die normalerweise aus Java stammen, das Verständnis erleichtern. Ganz am Ende werde ich alle Teile zusammenziehen und dann die Prägnanz erhöhen.
Zunächst muss die usingMethode aktualisiert werden, um sie verwenden zu können Try(auch hier ist Prägnanz nicht das Ziel). Es wird umbenannt in 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
}}})
Der Anfang der obigen tryUsingAutoCloseableMethode kann verwirrend sein, da sie anscheinend zwei Parameterlisten anstelle der üblichen Einzelparameterliste enthält. Dies nennt man Currying. Und ich werde nicht ins Detail gehen, wie Curry funktioniert oder wo es gelegentlich ist nützlich ist. Es stellt sich heraus, dass es für diesen speziellen Problembereich das richtige Werkzeug für den Job ist.
Als nächstes müssen wir eine Methode erstellen tryPrintToFile, die eine erstellt (oder eine vorhandene überschreibt) Fileund eine schreibt List[String]. Es verwendet ein, FileWriterdas von einem eingekapselt BufferedWriterist, das wiederum von einem eingekapselt ist PrintWriter. Um die Leistung zu steigern, wird eine Standardpuffergröße BufferedWriterdefiniert, die viel größer als die Standardpuffergröße ist.defaultBufferSize , und der Wert 65536 zugewiesen.
Hier ist der Code (und auch hier ist Prägnanz nicht das Ziel):
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)))}}}}
Die obige tryPrintToFileMethode ist insofern nützlich, als sie a List[String]als Eingabe nimmt und an a sendet File. Lassen Sie uns nun eine tryWriteToFileMethode erstellen , die a nimmt Stringund in a schreibtFile .
Hier ist der Code (und ich lasse Sie hier die Priorität der Prägnanz erraten):
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))}}}
Schließlich ist es nützlich, den Inhalt von a Fileals a abrufen zu können String. Während dies scala.io.Sourceeine bequeme Methode zum einfachen Abrufen des Inhalts von a darstellt File, closemuss die Methode verwendet werden Source, um die zugrunde liegenden JVM- und Dateisystem-Handles freizugeben. Wenn dies nicht erfolgt, wird die Ressource erst freigegeben, wenn der JVM GC (Garbage Collector) die SourceInstanz selbst freigegeben hat. Und selbst dann gibt es nur eine schwache JVM-Garantie, dass die finalizeMethode vom GC zur closeRessource aufgerufen wird . Dies bedeutet, dass es in der Verantwortung des Kunden liegt, das explizit aufzurufen . Dazu benötigen wir eine zweite Definition der using-Methode, die behandelt wird .close Methode , genauso wie es in der Verantwortung eines Kunden liegt, groß zu seinclose eine Instanz von zu ermittelnjava.lang.AutoCloseablescala.io.Source
Hier ist der Code dafür (immer noch nicht präzise):
Und hier ist ein Beispiel für die Verwendung in einem supereinfachen Zeilen-Streaming-Dateireader (der derzeit zum Lesen von durch Tabulatoren getrennten Dateien aus der Datenbankausgabe verwendet wird):
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))
Wenn Sie nun alles zusammen mit den extrahierten Importen zusammenführen (was das Einfügen in das Scala-Arbeitsblatt, das sowohl im Eclipse ScalaIDE- als auch im IntelliJ Scala-Plugin vorhanden ist, erheblich vereinfacht, um die Ausgabe auf den Desktop zu übertragen und die Prüfung mit einem Texteditor zu vereinfachen), So sieht der Code aus (mit erhöhter Prägnanz):
Als Scala / FP-Neuling habe ich viele Stunden (meistens mit Kopfkratzern) verbrannt, um mir das oben genannte Wissen und die oben genannten Lösungen zu verdienen. Ich hoffe, dies hilft anderen Scala / FP-Neulingen, diesen speziellen Lernbuckel schneller zu überwinden.
Unglaubliches Update. Das einzige Problem ist, dass Sie jetzt ungefähr 100 Codezeilen haben, die durch ersetzt werden könnten try-catch-finally. Liebe immer noch deine Leidenschaft.
Beobachter
1
@Observer Ich würde behaupten, dass dies eine ungenaue Aussage ist. Das Muster, das ich beschreibe, reduziert tatsächlich die Menge an Boilerplate, die ein Client schreiben muss, um eine ordnungsgemäße Behandlung des Schließens von AutoCloseables sicherzustellen, und aktiviert gleichzeitig das idiomatische FP-Muster von Scala für die Verwendung von scala.util.Try. Wenn Sie versuchen, die gleichen Effekte zu erzielen, die ich habe, indem Sie die try / catch / finally-Blöcke manuell ausschreiben, werden Sie wahrscheinlich mehr Boilerplate haben, als Sie sich vorstellen. Es gibt also einen signifikanten Lesbarkeitswert, wenn die gesamte Boilerplate in die 100 Zeilen der Scala-Funktion geschoben wird.
chaotic3quilibrium
1
Tut mir leid, wenn das in irgendeiner Weise beleidigend klang. Mein Punkt ist jedoch, dass eine solche Menge an Code nicht erforderlich ist, da dies durch einen nicht funktionalen Ansatz mit viel größerer Einfachheit erreicht werden könnte. Persönlich würde ich try-finally mit einigen zusätzlichen Schecks schreiben. Es ist nur kürzer. Wenn ich Wrapper verwenden wollte, sind ApacheUtils da, um die ganze Drecksarbeit zu nutzen. Darüber hinaus schließen alle Standard-Reader / Writer zugrunde liegende Streams, sodass Ihr Multipwrap nicht benötigt wird. PS: Ich habe meine Stimme von minus eins auf plus eins geändert, um Ihre Bemühungen zu unterstützen. Also, bitte, verdächtige mich nicht in schlechten Absichten.
Beobachter
Keine Beleidigung genommen.
chaotic3quilibrium
1
Ich verstehe Ihren Standpunkt. Danke für die Diskussion, ich muss ein bisschen darüber nachdenken. Einen schönen Tag noch!
Beobachter
3
Hier ist ein Beispiel für das Schreiben einiger Zeilen in eine Datei mit 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)}
Verwendung
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")}
Zusammenfassung - Java NIO (oder NIO.2 für Async) ist nach wie vor die umfassendste in Scala unterstützte Dateiverarbeitungslösung. Der folgende Code erstellt und schreibt Text in eine neue Datei:
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()}
Java-Bibliotheken importieren: IO und NIO
Ein ... kreieren Path Objekt mit dem von Ihnen gewählten Dateinamen
Konvertieren Sie Ihren Text, den Sie in eine Datei einfügen möchten, in ein Byte-Array
Holen Sie sich Ihre Datei als Stream: OutputStream
Übergeben Sie Ihr Byte-Array an die writeFunktion Ihres Ausgabestreams
Antworten:
Bearbeiten Sie 2019 (8 Jahre später), da Scala-IO nicht sehr aktiv ist, schlägt Li Haoyi seine eigene Bibliothek vor
lihaoyi/os-lib
, die er unten vorstellt .Im Juni 2019 erwähnt Xavier Guihot in seiner Antwort die Bibliothek
Using
, ein Dienstprogramm zur Durchführung der automatischen Ressourcenverwaltung.Bearbeiten (September 2011): Da Eduardo Costa nach Scala2.9 fragt und Rick-777 kommentiert, dass die Commit-Historie von scalax.IO seit Mitte 2009 so gut wie nicht mehr existiert ...
Scala-IO hat den Platz gewechselt: siehe GitHub-Repo von Jesse Eichar (ebenfalls auf SO ):
Ursprüngliche Antwort (Januar 2011) mit dem alten Ort für Scala-Io:
Wenn Sie nicht auf Scala2.9 warten möchten, können Sie die Scala-Inkubator / Scala-Io- Bibliothek verwenden.
(wie unter " Warum schließt Scala Source den zugrunde liegenden InputStream nicht? ")
Siehe die Beispiele
quelle
Dies ist eine der Funktionen, die in der Standard-Scala fehlen und die ich so nützlich fand, dass ich sie meiner persönlichen Bibliothek hinzufüge. (Sie sollten wahrscheinlich auch eine persönliche Bibliothek haben.) Der Code sieht folgendermaßen aus:
und es wird so verwendet:
quelle
Source
(Standardcodierung standardmäßig). Sie können natürlich zB einenenc: Option[String] = None
Parameter nach hinzufügen,f
wenn Sie dies als häufigen Bedarf empfinden.Ähnlich der Antwort von Rex Kerr, aber allgemeiner. Zuerst benutze ich eine Hilfsfunktion:
Dann benutze ich dies als:
und
etc.
quelle
Eine einfache Antwort:
quelle
import
aus denen Sie ?Eine andere Antwort geben, weil meine Änderungen anderer Antworten abgelehnt wurden.
Dies ist die prägnanteste und einfachste Antwort (ähnlich wie bei Garret Hall).
Dies ist vergleichbar mit Jus12, aber ohne die Ausführlichkeit und mit dem richtigen Code - Stil
Beachten Sie
try finally
, dass Sie weder die geschweiften Klammern noch Lambdas benötigen , und beachten Sie die Verwendung der Platzhaltersyntax. Beachten Sie auch eine bessere Benennung.quelle
implemented
Voraussetzung. Sie können den nicht implementierten Code nicht verwenden. Ich meine, Sie müssen sagen, wie Sie es finden, da es standardmäßig nicht verfügbar und nicht bekannt ist.Hier ist ein prägnanter Einzeiler, der die Scala-Compiler-Bibliothek verwendet:
Wenn Sie die Java-Bibliotheken verwenden möchten, können Sie alternativ diesen Hack ausführen:
quelle
scala.tools.nsc.io.File("/tmp/myFile.txt")
funktioniert in Scala 2.11.8.Ein Liner zum Speichern / Lesen zu / von
String
, mitjava.nio
.Dies ist nicht für große Dateien geeignet, erledigt aber die Aufgabe.
Einige Links:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
quelle
write
kopiert wirdcontents
, anstatt es in die Datei zu streamen, wodurch auf seinem Höhepunkt doppelt so viel Speicher verbraucht wird alscontents
allein.Unglücklicherweise für die Top-Antwort ist Scala-IO tot. Wenn es Ihnen nichts ausmacht, eine Abhängigkeit von Drittanbietern zu verwenden, sollten Sie meine OS-Lib-Bibliothek verwenden . Dies macht die Arbeit mit Dateien, Pfaden und dem Dateisystem sehr einfach:
Es verfügt über Einzeiler zum Schreiben in Dateien , zum Anhängen an Dateien , zum Überschreiben von Dateien und für viele andere nützliche / allgemeine Vorgänge
quelle
Eine Mikrobibliothek, die ich geschrieben habe: https://github.com/pathikrit/better-files
oder
quelle
Ab
Scala 2.13
dem Start bietet die Standardbibliothek ein dediziertes Dienstprogramm zur Ressourcenverwaltung :Using
.Es kann in diesem Fall mit Ressourcen wie
PrintWriter
oder verwendet werden,BufferedWriter
die erweitertAutoCloseable
werden, um in eine Datei zu schreiben und die Ressource anschließend zu schließen, egal was passiert:Zum Beispiel mit
java.io
api:Oder mit
java.nio
api:quelle
UPDATE am 2019 / Sep / 01:
finally
behobenException
, durch den das Original verschluckt wurde ,try
wenn derfinally
Code einException
Nachdem ich all diese Antworten zum einfachen Schreiben einer Datei in Scala überprüft hatte und einige davon sehr nett sind, hatte ich drei Probleme:
scala.util.Try
close
Methode auf jede abhängige Ressource in umgekehrten Reihenfolge - Hinweis: Schließen abhängige Ressourcen in umgekehrter Reihenfolge vor allem im Fall eines Fehlers ist ein selten verstanden Erfordernis Diejava.lang.AutoCloseable
Spezifikation, die dazu neigt, zu sehr schädlichen und schwer zu findenden Fehlern und Laufzeitfehlern zu führenBevor ich anfange, ist mein Ziel nicht prägnant. Dies soll Scala / FP-Anfängern, die normalerweise aus Java stammen, das Verständnis erleichtern. Ganz am Ende werde ich alle Teile zusammenziehen und dann die Prägnanz erhöhen.
Zunächst muss die
using
Methode aktualisiert werden, um sie verwenden zu könnenTry
(auch hier ist Prägnanz nicht das Ziel). Es wird umbenannt intryUsingAutoCloseable
:Der Anfang der obigen
tryUsingAutoCloseable
Methode kann verwirrend sein, da sie anscheinend zwei Parameterlisten anstelle der üblichen Einzelparameterliste enthält. Dies nennt man Currying. Und ich werde nicht ins Detail gehen, wie Curry funktioniert oder wo es gelegentlich ist nützlich ist. Es stellt sich heraus, dass es für diesen speziellen Problembereich das richtige Werkzeug für den Job ist.Als nächstes müssen wir eine Methode erstellen
tryPrintToFile
, die eine erstellt (oder eine vorhandene überschreibt)File
und eine schreibtList[String]
. Es verwendet ein,FileWriter
das von einem eingekapseltBufferedWriter
ist, das wiederum von einem eingekapselt istPrintWriter
. Um die Leistung zu steigern, wird eine StandardpuffergrößeBufferedWriter
definiert, die viel größer als die Standardpuffergröße ist.defaultBufferSize
, und der Wert 65536 zugewiesen.Hier ist der Code (und auch hier ist Prägnanz nicht das Ziel):
Die obige
tryPrintToFile
Methode ist insofern nützlich, als sie aList[String]
als Eingabe nimmt und an a sendetFile
. Lassen Sie uns nun einetryWriteToFile
Methode erstellen , die a nimmtString
und in a schreibtFile
.Hier ist der Code (und ich lasse Sie hier die Priorität der Prägnanz erraten):
Schließlich ist es nützlich, den Inhalt von a
File
als a abrufen zu könnenString
. Während diesscala.io.Source
eine bequeme Methode zum einfachen Abrufen des Inhalts von a darstelltFile
,close
muss die Methode verwendet werdenSource
, um die zugrunde liegenden JVM- und Dateisystem-Handles freizugeben. Wenn dies nicht erfolgt, wird die Ressource erst freigegeben, wenn der JVM GC (Garbage Collector) dieSource
Instanz selbst freigegeben hat. Und selbst dann gibt es nur eine schwache JVM-Garantie, dass diefinalize
Methode vom GC zurclose
Ressource aufgerufen wird . Dies bedeutet, dass es in der Verantwortung des Kunden liegt, das explizit aufzurufen . Dazu benötigen wir eine zweite Definition der using-Methode, die behandelt wird .close
Methode , genauso wie es in der Verantwortung eines Kunden liegt, groß zu seinclose
eine Instanz von zu ermittelnjava.lang.AutoCloseable
scala.io.Source
Hier ist der Code dafür (immer noch nicht präzise):
Und hier ist ein Beispiel für die Verwendung in einem supereinfachen Zeilen-Streaming-Dateireader (der derzeit zum Lesen von durch Tabulatoren getrennten Dateien aus der Datenbankausgabe verwendet wird):
Eine aktualisierte Version der oben genannten Funktion wurde als Antwort auf eine andere, aber verwandte StackOverflow-Frage bereitgestellt .
Wenn Sie nun alles zusammen mit den extrahierten Importen zusammenführen (was das Einfügen in das Scala-Arbeitsblatt, das sowohl im Eclipse ScalaIDE- als auch im IntelliJ Scala-Plugin vorhanden ist, erheblich vereinfacht, um die Ausgabe auf den Desktop zu übertragen und die Prüfung mit einem Texteditor zu vereinfachen), So sieht der Code aus (mit erhöhter Prägnanz):
Als Scala / FP-Neuling habe ich viele Stunden (meistens mit Kopfkratzern) verbrannt, um mir das oben genannte Wissen und die oben genannten Lösungen zu verdienen. Ich hoffe, dies hilft anderen Scala / FP-Neulingen, diesen speziellen Lernbuckel schneller zu überwinden.
quelle
try-catch-finally
. Liebe immer noch deine Leidenschaft.Hier ist ein Beispiel für das Schreiben einiger Zeilen in eine Datei mit Scalaz-Stream .
quelle
Um Samthebest und die Mitwirkenden vor ihm zu übertreffen, habe ich die Benennung und Prägnanz verbessert:
quelle
Keine Abhängigkeiten mit Fehlerbehandlung
Either
zur Fehlerbehandlung verwendetCode
Verwendung
quelle
Update 2019:
Zusammenfassung - Java NIO (oder NIO.2 für Async) ist nach wie vor die umfassendste in Scala unterstützte Dateiverarbeitungslösung. Der folgende Code erstellt und schreibt Text in eine neue Datei:
Path
Objekt mit dem von Ihnen gewählten DateinamenOutputStream
write
Funktion Ihres Ausgabestreamsquelle
Ähnlich wie bei dieser Antwort ist hier ein Beispiel mit
fs2
(Version 1.0.4):quelle
Diese Zeile hilft beim Schreiben einer Datei aus einem Array oder String.
quelle
Wenn Sie sowieso Akka Streams in Ihrem Projekt haben, bietet es einen Einzeiler:
Akka docs> Streaming File IO
quelle