Править 2019 год (8 лет спустя), поскольку Scala-IO не очень активен, если таковой имеется, Ли Хаои предлагает свою собственную библиотеку lihaoyi/os-lib, которую он представляет ниже .
В июне 2019 года Ксавье Гихот в своем ответе упоминает библиотеку Using, утилиту для автоматического управления ресурсами.
Редактирование (сентябрь 2011 г.): поскольку Эдуардо Коста спрашивает о Scala2.9 и с тех пор, как Рик-777 комментирует, что история коммитов scalax.IO практически отсутствует с середины 2009 г. ...
Зонтик-проект Scala IO состоит из нескольких подпроектов для различных аспектов и расширений IO.
Существует два основных компонента Scala IO:
Core - Core в основном занимается чтением и записью данных в произвольные источники и приемники и из них. Краеугольный камень черты Input, Outputи Seekableкоторые обеспечивают основной API.
Другие классы важности Resource, ReadCharsи WriteChars.
Файл - файл - это File(называемый Path) API, основанный на комбинации файловой системы Java 7 NIO и API SBT PathFinder. Pathи FileSystemявляются основными точками входа в 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)
Оригинальный ответ (январь 2011 г.) со старым местом для 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.UTF8val 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)}
Это действительно актуальное предложение для Scala 2.10? Использовать Scala IO? В ядре Scala еще ничего нет?
Фил
2
Я никогда не использовал scalax.io, но, судя по этим примерам, кажется, что его API-интерфейс довольно плохой. Смешивание методов для символьных и двоичных данных в одном интерфейсе не имеет большого смысла и, скорее всего, приведет к ошибкам кодирования, которые трудно найти. Дизайн java.io (Reader / Writer против InputStream / OutputStream) выглядит намного лучше.
jcsahnwaldt восстановить Монику
211
Это одна из функций, отсутствующих в стандартной версии Scala, которая мне показалась настолько полезной, что я добавил ее в свою личную библиотеку. (Вы, вероятно, тоже должны иметь личную библиотеку.) Код выглядит так:
def printToFile(f: java.io.File)(op: java.io.PrintWriter=>Unit){val p =new java.io.PrintWriter(f)try{ op(p)}finally{ p.close()}}
и он используется так:
import java.io._val data =Array("Five","strings","in","a","file!")
printToFile(newFile("example.txt")){ p =>
data.foreach(p.println)}
new java.io.PrintWriter () использует кодировку платформы по умолчанию, что, вероятно, означает, что файл результатов не очень переносим. Например, если вы хотите создать файл, который позже можете отправить по электронной почте, вам, вероятно, следует использовать конструктор PrintWriter, который позволяет указать кодировку.
jcsahnwaldt Восстановить Монику
@JonaChristopherSahnwaldt - Конечно, в особых случаях вы можете указать кодировку. Значение по умолчанию для платформы - это наиболее разумное значение по умолчанию в среднем. То же, что и с Source(кодировка по умолчанию по умолчанию). Вы, конечно, можете добавить, например, enc: Option[String] = Noneпараметр после, fесли вы считаете это общей потребностью.
Рекс Керр
6
@RexKerr - я не согласен. Следует указывать кодировку практически во всех случаях. Большинство ошибок кодирования, с которыми я сталкиваюсь, происходит потому, что люди не понимают или не думают о кодировании. Они используют значение по умолчанию и даже не знают его, потому что слишком много API позволяют им сойти с рук. В настоящее время наиболее разумным значением по умолчанию, вероятно, будет UTF-8. Возможно, вы работаете только с английским и другими языками, которые могут быть написаны в ASCII. Повезло тебе. Я живу в Германии, и мне пришлось починить больше сломанных умлаутов, чем я хочу вспомнить.
jcsahnwaldt Восстановить Монику
3
@JonaChristopherSahnwaldt - это причина иметь разумную кодировку по умолчанию, а не заставлять всех указывать ее постоянно. Но если вы работаете на Mac, а ваши файлы, написанные на Java, являются пустяковыми, потому что они не закодированы в Mac OS Roman, я не уверен, что это приносит больше пользы, чем вреда. Я думаю, это вина платформ, что они не договорились о кодировке. Как индивидуальный разработчик, ввод в строку действительно не решит проблему. (Все разработчики соглашаясь на UTF-8 будет, но тогда это может просто пойти по умолчанию.)
Rex Керр
@JonaChristopherSahnwaldt +10 за исправление всего сломанного умлаута. Не можете использовать молоток, возможно, дырокол? Или это уже дыры, которые нуждаются в заполнении, может быть, этот парень может помочь youtube.com/watch?v=E-eBBzWEpwE Но если серьезно, то влияние ASCII так пагубно в мире, согласитесь, его следует указать, а значение по умолчанию как UTF- 8
Давос,
50
Похожий на ответ Рекса Керра, но более общий. Сначала я использую вспомогательную функцию:
/**
* 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()}
Тогда я использую это как:
def writeToFile(fileName:String, data:String)=
using (newFileWriter(fileName)){
fileWriter => fileWriter.write(data)}
и
def appendToFile(fileName:String, textData:String)=
using (newFileWriter(fileName,true)){
fileWriter => using (newPrintWriter(fileWriter)){
printWriter => printWriter.println(textData)}}
Не поймите меня неправильно, мне нравится ваш код, и он очень познавательный, но чем больше я вижу такие конструкции для простых задач, тем больше он напоминает мне о старой шутке « Здравствуй, мир»: ariel.com.au/jokes/The_Evolution_of_a_Programmer .html :-) (+1 голос от меня).
Гринольдман
4
Если ты пишешь одну строчку, ничего не имеет значения. Если вы пишете важные программы (большие с постоянной потребностью в обслуживании и развитии), этот тип мышления приводит к наиболее быстрому и пагубному ухудшению качества программного обеспечения.
Рэндалл Шульц
3
Не у всех будут "глаза скалы" до некоторого уровня практики - забавно видеть, что этот пример кода прибывает из "Начинающего" Scala
asyncwait
asyncwait "начало" scala ... самое ироничное название когда-либо, обратите внимание: у меня есть книга ... и только сейчас я начинаю понимать это .. Я полагаю, чем я был на шаг раньше, чем "новичок" LOL: D ........
user1050817
1
Проблема здесь не в трюках Scala, а в многословности и плохом стиле. Я отредактировал это, чтобы сделать его более читабельным. После моего рефакторинга это всего 4 строки (ну, 4 с длиной строки IDE, здесь 6 используется, чтобы поместиться на экране). ИМХО, сейчас очень хороший ответ.
@samthebest не могли бы вы добавить библиотеки importиз?
Даниэль
1
Начиная с Java 7, используйте вместо этого java.nio.file: def writeToFile (file: String, stringToWrite: String): Unit = {val writer = Files.newBufferedWriter (Paths.get (file)), в конце концов, попробуйте writeer.write (stringToWrite) writer.close ()}
Э Шиндлер
20
Дать другой ответ, потому что мои правки других ответов были отклонены.
Это самый краткий и простой ответ (похожий на ответ Гаррета Холла)
File("filename").writeAll("hello world")
Это похоже на Jus12, но без многословия и с правильным стилем кода
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))
Обратите внимание, что вам НЕ нужны ни фигурные скобки try finally, ни лямбды, а обратите внимание на использование синтаксиса заполнителя. Также обратите внимание на лучшее именование.
Извините, но ваш код мыслимый, он не выполняет implementedпредварительных условий. Вы не можете использовать код, который не реализован. Я имею в виду, что вы должны сказать, как его найти, так как он не доступен по умолчанию и малоизвестен.
Val
15
Вот краткий однострочный текст с использованием библиотеки компилятора Scala:
@ChetanBhasin Вероятно, потому что writeбудет копировать contentsв новый байтовый массив вместо потоковой передачи его в файл, таким образом, на пике он использует вдвое больше памяти, чем contentsодин.
Даниэль Вернер
10
К сожалению для лучшего ответа, Scala-IO мертв. Если вы не возражаете против использования сторонней зависимости, подумайте об использовании моей библиотеки OS-Lib . Это делает работу с файлами, путями и файловой системой очень простой:
// 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")
И здесь - этот вопрос является одним из самых популярных при поиске, как написать файл с scala - теперь, когда ваш проект стал больше, возможно, вы захотите немного расширить свой ответ?
ASAC
6
Начиная Scala 2.13, стандартная библиотека обеспечивает специализированную утилиту управления ресурсами: Using.
В этом случае его можно использовать с такими ресурсами, как PrintWriterили BufferedWriterрасширяющимися AutoCloseableдля записи в файл и, несмотря ни на что, после этого закройте ресурс:
Начиная с Scala 2.13, предпочитайте использовать scala.util.Using
Исправлена ошибка, из-за которой finallyпроглатывался оригинальный Exceptionброшенный код, tryеслиfinallyException
Изучив все эти ответы о том, как легко написать файл в Scala, и некоторые из них довольно хороши, у меня возникло три вопроса:
В ответе Jus12 , использование каррирования для использования вспомогательного метода не очевидно для начинающих Scala / FP
Необходимо инкапсулировать ошибки более низкого уровня с scala.util.Try
Требуется показать Java-разработчикам, плохо знакомым с Scala / FP, как правильно вкладывать зависимые ресурсы, чтобы closeметод выполнялся на каждом зависимом ресурсе в обратном порядке. Примечание: закрытие зависимых ресурсов в обратном порядке. ОСОБЕННО В СЛУЧАЕ ОТКАЗА - редко понимаемое требование java.lang.AutoCloseableспецификация , которая имеет тенденцию приводить к очень пагубным и трудно найти ошибки и неудачи времени выполнения
Прежде чем начать, моя цель не краткость. Это облегчает понимание новичкам в Scala / FP, обычно начинающим с Java. В самом конце я соберу все кусочки вместе, а затем увеличу краткость.
Во-первых, usingметод должен быть обновлен для использования Try(опять же, краткость не является целью здесь). Он будет переименован в 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
}}})
Начало описанного выше tryUsingAutoCloseableметода может сбить с толку, потому что он, кажется, имеет два списка параметров вместо обычного списка с одним параметром. Это называется карри. И я не буду вдаваться в подробности, как работает карри или где это иногда полезно. Оказывается, для этой конкретной проблемной области это правильный инструмент для работы.
Далее нам нужно создать метод, tryPrintToFileкоторый создаст (или перезапишет существующий) Fileи напишет List[String]. Он использует a, FileWriterинкапсулированный a, BufferedWriterкоторый, в свою очередь, инкапсулируется a PrintWriter. А чтобы повысить производительность, размер буфера по умолчанию гораздо больше , чем по умолчанию для BufferedWriterопределен, defaultBufferSizeи присваивается значение 65536.
Вот код (и снова краткость здесь не является целью):
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)))}}}}
Вышеуказанный tryPrintToFileметод полезен тем, что он принимает в List[String]качестве входных данных и отправляет его в File. Давайте теперь создадим tryWriteToFileметод, который принимает Stringи записывает его в File.
Вот код (и я позволю вам угадать приоритет краткости здесь):
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))}}}
Наконец, полезно иметь возможность извлекать содержимое a Fileкак a String. В то время как scala.io.Sourceпредоставляет удобный метод для простого получения содержимого File, closeметод должен использоваться в, Sourceчтобы выпустить основные JVM и дескрипторы файловой системы. Если этого не сделать, ресурс не будет освобожден, пока JVM GC (Сборщик мусора) не сможет освободить сам Sourceэкземпляр. И даже в этом случае есть только слабая гарантия JVM, что finalizeметод будет вызван GC для closeресурса. Это означает, что ответственность за явный вызов closeметода лежит на клиенте , точно так же, как на клиенте лежит ответственность за получение доступа к closeэкземпляруjava.lang.AutoCloseable, Для этого нам понадобится второе определение метода using, который обрабатывает scala.io.Source.
И вот пример использования этого в супер простом считывателе потоковых файлов (в настоящее время используется для чтения файлов с разделителями табуляции из вывода базы данных):
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))
Теперь, собрав все это вместе с извлеченным импортом (упрощая вставку в рабочую таблицу Scala, присутствующую как в Eclipse ScalaIDE, так и в плагине IntelliJ Scala, чтобы упростить выгрузку выходных данных на рабочий стол для более удобного изучения в текстовом редакторе) Вот как выглядит код (с повышенной краткостью):
Будучи новичком в Scala / FP, я потратил много часов (в основном из-за головокружительного разочарования), зарабатывая эти знания и решения. Я надеюсь, что это поможет другим новичкам Scala / FP быстрее справиться с этой проблемой.
Невероятное обновление. Единственная проблема в том, что теперь у вас есть около 100 строк кода, которые можно заменить на try-catch-finally. Все еще любите свою страсть.
наблюдатель
1
@ Observer Я бы сказал, что это неточное утверждение. Шаблон, который я описываю, на самом деле уменьшает количество шаблонов, которые клиент должен написать, чтобы обеспечить правильную обработку закрытия AutoCloseables, а также включить идиоматический шаблон Scala FP с использованием scala.util.Try. Если вы попытаетесь добиться того же эффекта, что и я, вручную выписав блоки try / catch / finally, я думаю, вы обнаружите, что в итоге вы получите немного больше стандартного образца, чем вы себе представляете. Таким образом, существует значительная читаемость при вставке всего шаблона в 100 строк функции Scala.
chaotic3quilibrium
1
Извините, если это звучит оскорбительно. Тем не менее, я хочу сказать, что нет необходимости в таком количестве кода, потому что этого можно достичь с помощью нефункционального подхода с гораздо большей простотой. Лично я бы написал try-finally с некоторыми дополнительными проверками. Это просто короче. Если бы я хотел использовать обертки, ApacheUtils должен использовать всю грязную работу. Более того, все стандартные устройства чтения / записи закрывают основные потоки, поэтому многопоточность не требуется. PS: я изменил свой голос с минус одного на плюс один, чтобы поддержать ваши усилия. Поэтому, пожалуйста, не подозревайте меня в плохих намерениях.
наблюдатель
Без обид.
chaotic3quilibrium
1
Я понимаю вашу точку зрения. Спасибо за обсуждение, я должен немного подумать об этом. Хорошего дня!
наблюдатель
3
Вот пример записи некоторых строк в файл с использованием 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)}
использование
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")}
Резюме - Java NIO (или NIO.2 для async) по-прежнему является наиболее полным решением для обработки файлов, поддерживаемым в Scala. Следующий код создает и записывает некоторый текст в новый файл:
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: IO и NIO
Создать Pathобъект с выбранным вами именем файла
Преобразуйте ваш текст, который вы хотите вставить в файл, в байтовый массив
Получите ваш файл в виде потока: OutputStream
Передайте ваш байтовый массив в writeфункцию вашего выходного потока
Ответы:
Править 2019 год (8 лет спустя), поскольку Scala-IO не очень активен, если таковой имеется, Ли Хаои предлагает свою собственную библиотеку
lihaoyi/os-lib
, которую он представляет ниже .В июне 2019 года Ксавье Гихот в своем ответе упоминает библиотеку
Using
, утилиту для автоматического управления ресурсами.Редактирование (сентябрь 2011 г.): поскольку Эдуардо Коста спрашивает о Scala2.9 и с тех пор, как Рик-777 комментирует, что история коммитов scalax.IO практически отсутствует с середины 2009 г. ...
Scala-IO изменил место: посмотрите репозиторий GitHub от Джесси Эйхара (также на SO ):
Оригинальный ответ (январь 2011 г.) со старым местом для scala-io:
Если вы не хотите ждать Scala2.9, вы можете использовать библиотеку scala-инкубатор / scala-io .
(как упоминалось в разделе « Почему источник Scala не закрывает базовый InputStream? »)
Посмотреть образцы
источник
Это одна из функций, отсутствующих в стандартной версии Scala, которая мне показалась настолько полезной, что я добавил ее в свою личную библиотеку. (Вы, вероятно, тоже должны иметь личную библиотеку.) Код выглядит так:
и он используется так:
источник
Source
(кодировка по умолчанию по умолчанию). Вы, конечно, можете добавить, например,enc: Option[String] = None
параметр после,f
если вы считаете это общей потребностью.Похожий на ответ Рекса Керра, но более общий. Сначала я использую вспомогательную функцию:
Тогда я использую это как:
и
и т.п.
источник
Простой ответ:
источник
import
из?Дать другой ответ, потому что мои правки других ответов были отклонены.
Это самый краткий и простой ответ (похожий на ответ Гаррета Холла)
Это похоже на Jus12, но без многословия и с правильным стилем кода
Обратите внимание, что вам НЕ нужны ни фигурные скобки
try finally
, ни лямбды, а обратите внимание на использование синтаксиса заполнителя. Также обратите внимание на лучшее именование.источник
implemented
предварительных условий. Вы не можете использовать код, который не реализован. Я имею в виду, что вы должны сказать, как его найти, так как он не доступен по умолчанию и малоизвестен.Вот краткий однострочный текст с использованием библиотеки компилятора Scala:
В качестве альтернативы, если вы хотите использовать библиотеки Java, вы можете сделать это взломать:
источник
scala.tools.nsc.io.File("/tmp/myFile.txt")
работает в Scala 2.11.8.Один лайнер для сохранения / чтения в / из
String
, используяjava.nio
.Это не подходит для больших файлов, но сделает работу.
Некоторые ссылки:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
источник
write
будет копироватьcontents
в новый байтовый массив вместо потоковой передачи его в файл, таким образом, на пике он использует вдвое больше памяти, чемcontents
один.К сожалению для лучшего ответа, Scala-IO мертв. Если вы не возражаете против использования сторонней зависимости, подумайте об использовании моей библиотеки OS-Lib . Это делает работу с файлами, путями и файловой системой очень простой:
Он имеет одну строку для записи в файлы , добавления к файлам , перезаписи файлов и многих других полезных / общих операций
источник
Микро библиотека, которую я написал: https://github.com/pathikrit/better-files
или
источник
Начиная
Scala 2.13
, стандартная библиотека обеспечивает специализированную утилиту управления ресурсами:Using
.В этом случае его можно использовать с такими ресурсами, как
PrintWriter
илиBufferedWriter
расширяющимисяAutoCloseable
для записи в файл и, несмотря ни на что, после этого закройте ресурс:Например, с
java.io
API:Или с
java.nio
API:источник
ОБНОВЛЕНИЕ 2019 / сентябрь / 01:
finally
проглатывался оригинальныйException
брошенный код,try
еслиfinally
Exception
Изучив все эти ответы о том, как легко написать файл в Scala, и некоторые из них довольно хороши, у меня возникло три вопроса:
scala.util.Try
close
метод выполнялся на каждом зависимом ресурсе в обратном порядке. Примечание: закрытие зависимых ресурсов в обратном порядке. ОСОБЕННО В СЛУЧАЕ ОТКАЗА - редко понимаемое требованиеjava.lang.AutoCloseable
спецификация , которая имеет тенденцию приводить к очень пагубным и трудно найти ошибки и неудачи времени выполненияПрежде чем начать, моя цель не краткость. Это облегчает понимание новичкам в Scala / FP, обычно начинающим с Java. В самом конце я соберу все кусочки вместе, а затем увеличу краткость.
Во-первых,
using
метод должен быть обновлен для использованияTry
(опять же, краткость не является целью здесь). Он будет переименован вtryUsingAutoCloseable
:Начало описанного выше
tryUsingAutoCloseable
метода может сбить с толку, потому что он, кажется, имеет два списка параметров вместо обычного списка с одним параметром. Это называется карри. И я не буду вдаваться в подробности, как работает карри или где это иногда полезно. Оказывается, для этой конкретной проблемной области это правильный инструмент для работы.Далее нам нужно создать метод,
tryPrintToFile
который создаст (или перезапишет существующий)File
и напишетList[String]
. Он использует a,FileWriter
инкапсулированный a,BufferedWriter
который, в свою очередь, инкапсулируется aPrintWriter
. А чтобы повысить производительность, размер буфера по умолчанию гораздо больше , чем по умолчанию дляBufferedWriter
определен,defaultBufferSize
и присваивается значение 65536.Вот код (и снова краткость здесь не является целью):
Вышеуказанный
tryPrintToFile
метод полезен тем, что он принимает вList[String]
качестве входных данных и отправляет его вFile
. Давайте теперь создадимtryWriteToFile
метод, который принимаетString
и записывает его вFile
.Вот код (и я позволю вам угадать приоритет краткости здесь):
Наконец, полезно иметь возможность извлекать содержимое a
File
как aString
. В то время какscala.io.Source
предоставляет удобный метод для простого получения содержимогоFile
,close
метод должен использоваться в,Source
чтобы выпустить основные JVM и дескрипторы файловой системы. Если этого не сделать, ресурс не будет освобожден, пока JVM GC (Сборщик мусора) не сможет освободить самSource
экземпляр. И даже в этом случае есть только слабая гарантия JVM, чтоfinalize
метод будет вызван GC дляclose
ресурса. Это означает, что ответственность за явный вызовclose
метода лежит на клиенте , точно так же, как на клиенте лежит ответственность за получение доступа кclose
экземпляруjava.lang.AutoCloseable
, Для этого нам понадобится второе определение метода using, который обрабатываетscala.io.Source
.Вот код для этого (все еще не является кратким):
И вот пример использования этого в супер простом считывателе потоковых файлов (в настоящее время используется для чтения файлов с разделителями табуляции из вывода базы данных):
Обновленная версия вышеупомянутой функции была предоставлена в ответ на различный , но связанный StackOverflow вопрос .
Теперь, собрав все это вместе с извлеченным импортом (упрощая вставку в рабочую таблицу Scala, присутствующую как в Eclipse ScalaIDE, так и в плагине IntelliJ Scala, чтобы упростить выгрузку выходных данных на рабочий стол для более удобного изучения в текстовом редакторе) Вот как выглядит код (с повышенной краткостью):
Будучи новичком в Scala / FP, я потратил много часов (в основном из-за головокружительного разочарования), зарабатывая эти знания и решения. Я надеюсь, что это поможет другим новичкам Scala / FP быстрее справиться с этой проблемой.
источник
try-catch-finally
. Все еще любите свою страсть.Вот пример записи некоторых строк в файл с использованием scalaz-stream .
источник
Чтобы превзойти samthebest и участников до него, я улучшил наименование и краткость:
источник
Нет зависимостей, с обработкой ошибок
Either
для обработки ошибокКод
использование
источник
2019 Обновление:
Резюме - Java NIO (или NIO.2 для async) по-прежнему является наиболее полным решением для обработки файлов, поддерживаемым в Scala. Следующий код создает и записывает некоторый текст в новый файл:
Path
объект с выбранным вами именем файлаOutputStream
write
функцию вашего выходного потокаисточник
Аналогично этому ответу , вот пример с
fs2
(версия 1.0.4):источник
Эта строка помогает записать файл из массива или строки.
источник
Если у вас в любом случае есть Akka Streams в вашем проекте, он предоставляет одну строку:
Akka docs> Потоковый файл IO
источник