Як читати файл як байтовий масив у Scala


77

Я можу знайти безліч прикладів, але, схоже, вони або покладаються переважно на бібліотеки Java, або просто читають символи / рядки / тощо.

Я просто хочу прочитати якийсь файл і отримати байтовий масив із бібліотеками Scala - може хтось допоможе мені в цьому?


3
Я думаю, що покладатися на бібліотеки Java - це те, що (майже?) Робили б усі, включаючи бібліотеку Scala. Див., Наприклад, вихідний код scala.io.Source.
Філіпп

2
Ви не використовуєте іншу мову, а лише стандартний API JVM, який виявився достатньо хорошим, щоб не потребувати заміни!
Duncan McGregor

4
Ну, як ви думаєте, як реалізовані класи Java? У глибині душі десь є власний метод: він має лише підпис, не реалізує Java і покладається на реалізацію C, специфічну для ОС. Хіба це теж не обман? :)
Філіпп

2
Слід сказати, що Scala на .Net робить це більш актуальною проблемою.
Duncan McGregor

4
@Philippe: Звичайно, а використання C - це лише обман на збірці: P ... Я мав на увазі просто те, що межа між мовами, як правило, досить чітко визначена, Scala та Java наче переплавляються одна в одну.
fgysin відновив Моніку

Відповіді:


134

Java 7:

import java.nio.file.{Files, Paths}

val byteArray = Files.readAllBytes(Paths.get("/path/to/file"))

Я вважаю, що це найпростіший можливий спосіб. Просто використовуючи тут існуючі інструменти. NIO.2 - це чудово.


1
Я думаю, що кожен, хто не пов'язаний з jvm <7, повинен цим користуватися.
fedesilva

45

Це має спрацювати (Scala 2.8):

val bis = new BufferedInputStream(new FileInputStream(fileName))
val bArray = Stream.continually(bis.read).takeWhile(-1 !=).map(_.toByte).toArray

Я думаю, що це чудовий приклад обтікання функції Java API для отримання семантики Stream. Цінується.
qu1j0t3

3
val bis = new java.io.BufferedInputStream(new java.io.FileInputStream(fileName)); якщо у вас немає імпортованих шляхів Java
BeniBela

1
Застосовуючи цей підхід, закриття файлу також необхідне або це неявно?
Макс.

1
Вам потрібно закрити його самостійно
Тоні К.

14
Цей підхід є повільним, оскільки йому потрібно обробити кожен байт. В ідеалі операції вводу-виводу повинні базуватися на блоці.
Діббеке

6
val is = new FileInputStream(fileName)
val cnt = is.available
val bytes = Array.ofDim[Byte](cnt)
is.read(bytes)
is.close()

1
Це не дійсне рішення. З javadoc з InputStream. Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
Доступний

5

Бібліотека scala.io.Source є проблематичною, НЕ ВИКОРИСТОВУЙТЕ ЇЇ при читанні двійкових файлів.

Помилку можна відтворити відповідно до інструкцій тут: https://github.com/liufengyun/scala-bug

У файлі data.binвін містить шістнадцяткову систему 0xea, яка є 11101010двійковою і має бути перетворена 234в десяткову.

main.scalaФайл містить два способи , щоб прочитати файл:

import scala.io._
import java.io._

object Main {
  def main(args: Array[String]) {
    val ss = Source.fromFile("data.bin")
    println("Scala:" + ss.next.toInt)
    ss.close

    val bis = new BufferedInputStream(new FileInputStream("data.bin"))
    println("Java:" + bis.read)
    bis.close
  }
}

Коли я запускаю scala main.scala, програма виводить наступне:

Scala:205
Java:234

Бібліотека Java генерує правильний результат, тоді як бібліотека Scala - ні.


10
Якщо для кодування встановлено значення Source.fromFile("data.bin", "ISO8859-1"), воно працює добре.
fengyun liu

6
Можливо, це корисно, але насправді, це не відповідь. Введення нової проблеми у відповідь не є конструктивним і належить десь іншому.
Бенджамін

4

Ви також можете розглянути можливість використання scalax.io :

scalax.io.Resource.fromFile(fileName).byteArray

5
Помітив, що останні дії щодо цього сховища були 6 років тому - чи все ще це актуально?
akauppi

2

Ви можете використовувати Apache Commons Compress IOUtils

import org.apache.commons.compress.utils.IOUtils

val file = new File("data.bin")
IOUtils.toByteArray(new FileInputStream(file))

1
Мені довелося імпортувати import org.apache.commons.io.IOUtils замість запропонованого імпорту.
ніїд

0

Я використовував наведений нижче код для читання файлу CSV.

import scala.io.StdIn.readLine
import scala.io.Source.fromFile

readFile("C:/users/xxxx/Downloads/", "39025968_ccccc_1009.csv")

def readFile(loc :String,filenm :String): Unit ={

  var flnm = fromFile(s"$loc$filenm") // Imported fromFile package

  println("Files testing")
  /*for (line <- flnm.getLines()) {
    printf("%4d %s\n", line.length, line)
  }*/
  flnm.getLines().foreach(println) // getLines() is imported from readLines.
  flnm.close() 
}

1
З таким старим запитанням (заданим понад 9 років тому) та з такою кількістю вже надісланих відповідей корисно вказати, чим ваша нова відповідь відрізняється від попередніх відповідей. (І включення коду, який було прокоментовано, виглядає просто неакуратно.)
jwvh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.