Scala文件操作示例代碼講解
1. 讀取數(shù)據(jù)
在Scala語言的 Source單例對(duì)象 中, 提供了一些非常便捷的方法, 從而使開發(fā)者可以快速的從指定數(shù)據(jù)源(文本文件, URL地址等)中獲取數(shù)據(jù), 在使用 Source單例對(duì)象 之前, 需要先導(dǎo)包, 即 import scala.io.Source.
1.1 按行讀取
我們可以以 行 為單位, 來讀取數(shù)據(jù)源中的數(shù)據(jù), 返回值是一個(gè) 迭代器類型的對(duì)象 . 然后通過 toArray, toList
方法, 將這些數(shù)據(jù)放到數(shù)組或者列表中即可.
注意: Source類擴(kuò)展自Iterator[Char]
格式
//1. 獲取數(shù)據(jù)源文件對(duì)象. val source:BufferedSource = Source.fromFile("數(shù)據(jù)源文件的路徑","編碼表") //2. 以行為單位讀取數(shù)據(jù). val lines:Iterator[String] = source.getLines() //3. 將讀取到的數(shù)據(jù)封裝到列表中. val list1:List[String] = lines.toList //4. 千萬別忘記關(guān)閉Source對(duì)象. source.close()
需求
在當(dāng)前項(xiàng)目下創(chuàng)建data文件夾, 并在其中創(chuàng)建1.txt文本文件, 文件內(nèi)容如下:
好好學(xué)習(xí), 天天向上!
Hadoop, Zookeeper, Flume, Spark
Flink, Sqoop, HBase
以行為單位讀取該文本文件中的數(shù)據(jù), 并打印結(jié)果.
參考代碼
import scala.io.Source object ClassDemo01 { def main(args: Array[String]): Unit = { //1. 獲取數(shù)據(jù)源對(duì)象. val source = Source.fromFile("./data/1.txt") //2.通過getLines()方法, 逐行獲取文件中的數(shù)據(jù). var lines: Iterator[String] = source.getLines() //3. 將獲取到的每一條數(shù)據(jù)都封裝到列表中. val list1 = lines.toList //4. 打印結(jié)果 for(s <- list1) println(s) //5. 記得關(guān)閉source對(duì)象. source.close() } }
1.2 按字符讀取
Scala還提供了 以字符為單位讀取數(shù)據(jù) 這種方式, 這種用法類似于迭代器, 讀取數(shù)據(jù)之后, 我們可以通過 hasNext(),next()方法 , 靈活的獲取數(shù)據(jù).
Scala使用source.buffered方法按字符讀取文件
什么是source.buffered方法
source.buffered方法是scala.io.Source類的一個(gè)成員方法,它可以將一個(gè)Source對(duì)象轉(zhuǎn)換為一個(gè)BufferedSource對(duì)象。BufferedSource對(duì)象是一個(gè)實(shí)現(xiàn)了BufferedIterator特質(zhì)的對(duì)象,它可以提供一個(gè)緩沖區(qū),用來存儲(chǔ)未被消費(fèi)的元素。這樣可以提高讀取文件的效率,也可以方便地查看下一個(gè)元素而不消費(fèi)它。
如何使用source.buffered方法
要使用source.buffered方法,首先需要導(dǎo)入scala.io.Source類,并創(chuàng)建一個(gè)Source對(duì)象,然后調(diào)用其buffered方法,得到一個(gè)BufferedSource對(duì)象。例如,以下代碼創(chuàng)建了一個(gè)從文件中獲取的Source對(duì)象,并轉(zhuǎn)換為一個(gè)BufferedSource對(duì)象:
import scala.io.Source // 創(chuàng)建一個(gè)從文件中獲取的Source對(duì)象 val source = Source.fromFile("demo.txt") // 調(diào)用buffered方法,得到一個(gè)BufferedSource對(duì)象 val buffered = source.buffered
然后,可以使用BufferedSource對(duì)象的各種方法來按字符讀取文件。例如,以下代碼使用head方法來查看下一個(gè)字符,使用next方法來消費(fèi)下一個(gè)字符,并打印出來:
// 使用head方法查看下一個(gè)字符 println(buffered.head) // 使用next方法消費(fèi)下一個(gè)字符 println(buffered.next()) // 繼續(xù)使用head方法查看下一個(gè)字符 println(buffered.head) // 繼續(xù)使用next方法消費(fèi)下一個(gè)字符 println(buffered.next())
最后,需要關(guān)閉Source對(duì)象,釋放資源:
// 關(guān)閉Source對(duì)象source.close()
一個(gè)示例
下面給出一個(gè)完整的示例,演示如何使用source.buffered方法來按字符讀取文件,并打印出來。
首先,準(zhǔn)備一個(gè)文本文件demo.txt,內(nèi)容如下:
Hello, Scala!
你好,Scala!
然后,編寫以下代碼:
import scala.io.Source // 創(chuàng)建一個(gè)從文件中獲取的Source對(duì)象,并轉(zhuǎn)換為一個(gè)BufferedSource對(duì)象 val buffered = Source.fromFile("demo.txt").buffered // 循環(huán)判斷是否有下一個(gè)元素 while (buffered.hasNext) { // 打印出當(dāng)前元素,并消費(fèi)掉 print(buffered.next()) } // 關(guān)閉Source對(duì)象 buffered.close()
最后,運(yùn)行程序,可以看到輸出結(jié)果如下:
Hello, Scala!
你好,Scala!
1.3 讀取詞法單元和數(shù)字
所謂的詞法單元指的是 以特定符號(hào)間隔開的字符串 , 如果數(shù)據(jù)源文件中的數(shù)據(jù)都是 數(shù)字形式的字符串 , 我們可以很方便的從文件中直接獲取這些數(shù)據(jù), 例如:
10 2 5
11 2
5 1 3 2
格式
//1. 獲取數(shù)據(jù)源文件對(duì)象. val source:BufferedSource = Source.fromFile("數(shù)據(jù)源文件的路徑","編碼表") //2. 讀取詞法單元. // \s表示空白字符(空格, \t, \r, \n等) val arr:Array[String] = source.mkString.split("\\s+") //3. 將字符串轉(zhuǎn)成對(duì)應(yīng)的整數(shù) val num = strNumber.map(_.toInt) //4. 千萬別忘記關(guān)閉Source對(duì)象. source.close()
參考代碼
將上面的數(shù)字存入2.txt
import scala.io.Source object ClassDemo03 { def main(args: Array[String]): Unit = { val source = Source.fromFile("./data/2.txt") // \s表示空白字符(空格, \t, \r, \n等) val strNumber = source.mkString.split("\\s+") //將字符串轉(zhuǎn)成對(duì)應(yīng)的整數(shù) val num = strNumber.map(_.toInt) for(a <- num) println(a + 1) } }
1.4 從URL或者其他源讀取數(shù)據(jù)
Scala中提供了一種方式, 可以讓我們直接從指定的URL路徑, 或者其他源(例如: 特定的字符串)中直接讀取數(shù)據(jù)。
格式 從URL地址中讀取數(shù)據(jù)
//1. 獲取數(shù)據(jù)源文件對(duì)象. val source = Source.fromURL("https://www.csdn.net") //2. 將數(shù)據(jù)封裝到字符串中并打印. println(source.mkString)
從其他源讀取數(shù)據(jù)
//1. 獲取數(shù)據(jù)源文件對(duì)象. val str = Source.fromString("CSDN") println(str.getLines())
需求
- 讀取
https://www.csdn.net
頁面的數(shù)據(jù), 并打印結(jié)果. - 直接讀取字符串
CSDN
, 并打印結(jié)果.
參考代碼
import scala.io.Source object ClassDemo04 { def main(args: Array[String]): Unit = { val source = Source.fromURL("https://www.csdn.net") println(source.mkString) val str = Source.fromString("CSDN") println(str.getLines()) } }
1.5 讀取二進(jìn)制文件
Scala沒有提供讀取二進(jìn)制文件的方法, 我們需要通過Java類庫(kù)來實(shí)現(xiàn).
需求 已知項(xiàng)目的data文件夾下有 05.png
這張圖片, 請(qǐng)讀取該圖片數(shù)據(jù), 并將讀取到的字節(jié)數(shù)打印到控制臺(tái)上. 參考代碼
object ClassDemo05 { def main(args: Array[String]): Unit = { val file = new File("./data/04.png") val fis = new FileInputStream(file) val bys = new Array[Byte](file.length().toInt) fis.read(bys) fis.close() println(bys.length) } }
2. 寫入文件
2.1 使用java.io.PrintWriter類
java.io.PrintWriter類是Java提供的一個(gè)用于寫入文本文件的類。它可以接受一個(gè)文件、一個(gè)輸出流或一個(gè)字符串作為參數(shù),然后通過調(diào)用其write方法來向文件中寫入數(shù)據(jù)。例如,以下代碼可以向文件hello.txt中寫入一行文本:
import java.io._ val pw = new PrintWriter(new File("hello.txt")) pw.write("Hello, world") pw.close()
使用PrintWriter類寫入文件時(shí),有兩個(gè)需要注意的問題:
- PrintWriter類不會(huì)拋出異常,而是設(shè)置一個(gè)布爾標(biāo)志來表示是否發(fā)生了錯(cuò)誤??梢酝ㄟ^調(diào)用其checkError方法來檢查是否有錯(cuò)誤發(fā)生。
- PrintWriter類默認(rèn)使用平臺(tái)的字符編碼,這可能導(dǎo)致不同平臺(tái)之間的不一致。可以通過指定字符編碼來避免這個(gè)問題。例如,以下代碼使用了UTF-8編碼:
val pw = new PrintWriter(new File("hello.txt"), "UTF-8")
2.2 使用java.io.FileWriter類
java.io.FileWriter類是Java提供的另一個(gè)用于寫入文本文件的類。它是OutputStreamWriter的子類,可以接受一個(gè)文件或一個(gè)字符串作為參數(shù),然后通過調(diào)用其write方法來向文件中寫入數(shù)據(jù)。例如,以下代碼可以向文件test.txt中寫入一行文本:
import java.io._ val file = new File("test.txt") val bw = new BufferedWriter(new FileWriter(file)) bw.write("We are learning Scala programming language") bw.close()
使用FileWriter類寫入文件時(shí),有兩個(gè)需要注意的問題:
- FileWriter類會(huì)拋出IOExceptions異常,所以需要使用try-catch-finally語句來處理異常和關(guān)閉文件。
- FileWriter類默認(rèn)使用平臺(tái)的字符編碼,這可能導(dǎo)致不同平臺(tái)之間的不一致。FileWriter類沒有提供指定字符編碼的構(gòu)造器,所以如果需要指定字符編碼,可以使用OutputStreamWriter類代替。例如,以下代碼使用了UTF-8編碼:
val file = new File("test.txt") val bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) bw.write("We are learning Scala programming language") bw.close()
2.3 使用java.io.FileOutputStream類
FileOutputStream是Java提供的一個(gè)用于寫入二進(jìn)制文件的類,它是OutputStream的子類,可以接受一個(gè)文件或一個(gè)字符串作為參數(shù),然后通過調(diào)用其write方法來向文件中寫入字節(jié)數(shù)據(jù)。例如,以下代碼可以向文件data.bin中寫入一個(gè)整數(shù):
import java.io._ val file = new File("data.bin") val fos = new FileOutputStream(file) fos.write(42) fos.close()
FileOutputStream類會(huì)拋出IOExceptions異常,所以需要使用try-catch-finally語句來處理異常和關(guān)閉文件。
已收到消息. FileOutputStream是Java提供的一個(gè)用于寫入二進(jìn)制文件的類,它是OutputStream的子類,可以接受一個(gè)文件或一個(gè)字符串作為參數(shù),然后通過調(diào)用其write方法來向文件中寫入字節(jié)數(shù)據(jù)。例如,以下代碼可以向文件data.bin中寫入一個(gè)整數(shù): scala import java.io._ val file = new File("data.bin") val fos = new FileOutputStream(file) fos.write(42) fos.close()
FileOutputStream類會(huì)拋出IOExceptions異常,所以需要使用try-catch-finally語句來處理異常和關(guān)閉文件。
2.4 幾種寫入的區(qū)別
因?yàn)镕ileOutputStream類有兩種構(gòu)造器,一種接受一個(gè)文件對(duì)象作為參數(shù),一種接受一個(gè)字符串作為參數(shù)。如果接受一個(gè)字符串作為參數(shù),那么它會(huì)自動(dòng)創(chuàng)建一個(gè)文件對(duì)象。所以,以下兩種寫法是等價(jià)的:
val pw = new FileOutputStream(new File("./data/3.txt")) val pw = new FileOutputStream("./data/3.txt")
但是,如果使用PrintWriter類或FileWriter類,那么就必須使用一個(gè)文件對(duì)象作為參數(shù),不能使用一個(gè)字符串。所以,以下兩種寫法是不等價(jià)的:
val pw = new PrintWriter(new File("./data/3.txt")) val pw = new PrintWriter("./data/3.txt") // 錯(cuò)誤
2.5 使用第三方庫(kù)
除了Java提供的類之外,還有一些第三方庫(kù)可以用來寫入文件,例如Apache Commons IO1和os-lib2等。這些庫(kù)通常提供了更簡(jiǎn)潔和高效的API,也支持更多的功能和格式。例如,以下代碼使用了Apache Commons IO庫(kù)的FileUtils類來寫入文件,并指定了字符編碼:
import org.apache.commons.io.FileUtils FileUtils.writeStringToFile(new File("test.txt"), "Hello, world", "UTF-8")
以下代碼使用了os-lib庫(kù)的os.File對(duì)象來寫入文件,并返回一個(gè)字節(jié)長(zhǎng)度:
import os._ os.write(os.pwd / "test.txt", "Hello, world")
3. Scala序列化和反序列化
3.1 什么是序列化和反序列化
在Scala中,如果想將對(duì)象傳輸?shù)狡渌摂M機(jī),或者臨時(shí)存儲(chǔ),就可以通過序列化和反序列化來實(shí)現(xiàn)了。
- 序列化:把對(duì)象寫到文件中的過程。
- 反序列化:從文件中加載對(duì)象的過程。
3.2 如何實(shí)現(xiàn)序列化和反序列化
一個(gè)類的對(duì)象要想實(shí)現(xiàn)序列化和反序列化操作,則該類必須繼承Serializable特質(zhì)。Serializable特質(zhì)是一個(gè)空特質(zhì),它沒有任何方法和字段,只是用來標(biāo)記一個(gè)類是否可以被序列化和反序列化。
要實(shí)現(xiàn)序列化操作,可以使用java.io.ObjectOutputStream類,它是一個(gè)用于寫入對(duì)象的輸出流。它可以接受一個(gè)輸出流作為參數(shù),然后通過調(diào)用其writeObject方法來寫入對(duì)象。
要實(shí)現(xiàn)反序列化操作,可以使用java.io.ObjectInputStream類,它是一個(gè)用于讀取對(duì)象的輸入流。它可以接受一個(gè)輸入流作為參數(shù),然后通過調(diào)用其readObject方法來讀取對(duì)象。
3.3 一個(gè)示例
下面給出一個(gè)簡(jiǎn)單的示例,演示如何使用case class和object來實(shí)現(xiàn)序列化和反序列化操作。
首先,定義一個(gè)case class Person,屬性為姓名和年齡。注意,case class會(huì)自動(dòng)繼承Serializable特質(zhì),所以不需要顯式地寫出來。
// 定義一個(gè)case class Person case class Person(var name: String, var age: Int)
然后,創(chuàng)建Person樣例類的對(duì)象p,并通過序列化操作將對(duì)象p寫入到項(xiàng)目下的data文件夾下的4.txt文本文件中。
// 創(chuàng)建Person樣例類的對(duì)象p val p = Person("張三", 23) // 創(chuàng)建一個(gè)ObjectOutputStream對(duì)象,傳入一個(gè)輸出流作為參數(shù) val oos = new ObjectOutputStream(new FileOutputStream("./data/4.txt")) // 調(diào)用writeObject方法,將對(duì)象p寫入到輸出流中 oos.writeObject(p) // 關(guān)閉輸出流 oos.close()
最后,通過反序列化操作從項(xiàng)目下的data文件夾下的4.txt文件中,讀取對(duì)象p,并打印出來。
// 創(chuàng)建一個(gè)ObjectInputStream對(duì)象,傳入一個(gè)輸入流作為參數(shù) val ois = new ObjectInputStream(new FileInputStream("./data/4.txt")) // 調(diào)用readObject方法,從輸入流中讀取對(duì)象,并轉(zhuǎn)換為Person類型 var p: Person = ois.readObject().asInstanceOf[Person] // 打印對(duì)象p println(p) // 關(guān)閉輸入流 ois.close()
3.4 使用注解
除了使用Serializable特質(zhì)之外,還可以使用@SerialVersionUID注解來指定一個(gè)版本號(hào)。這樣可以避免不同版本的類之間的兼容性問題。例如,以下代碼定義了一個(gè)普通的類,并添加了注解:
import java.io._ // 使用@SerialVersionUID注解指定版本號(hào)為100L @SerialVersionUID(100L) // 定義一個(gè)普通的類,并繼承Serializable特質(zhì) class Person(var name: String, var age: Int) extends Serializable
然后,可以使用相同的方式進(jìn)行序列化和反序列化操作:
val p = new Person("張三", 23) val oos = new ObjectOutputStream(new FileOutputStream("./data/4.txt")) oos.writeObject(p) oos.close() val ois = new ObjectInputStream(new FileInputStream("./data/4.txt")) var p: Person = ois.readObject().asInstanceOf[Person] println(p)
案例-學(xué)員成績(jī)表
概述
已知項(xiàng)目下的data文件夾的student.txt文本文件中, 記錄了一些學(xué)員的成績(jī), 如下: 格式為: 姓名 語文成績(jī) 數(shù)學(xué)成績(jī) 英語成績(jī)
張三 37 90 100
李四 90 73 81
王五 60 90 76
趙六 89 21 72
田七 100 100 100
按照學(xué)員的總成績(jī)降序排列后, 按照 姓名 語文成績(jī) 數(shù)學(xué)成績(jī) 英語成績(jī) 總成績(jī) 的格式, 將數(shù)據(jù)寫到項(xiàng)目下的data文件夾的stu.txt文件中.
** 步驟**
- 定義樣例類Person, 屬性為: 姓名, 語文成績(jī), 數(shù)學(xué)成績(jī), 英語成績(jī), 且該類中有一個(gè)獲取總成績(jī)的方法.
- 讀取指定文件(./data/student.txt)中所有的數(shù)據(jù), 并將其封裝到List列表中.
- 定義可變的列表ListBuffer[Student], 用來記錄所有學(xué)生的信息.
- 遍歷第二步獲取到的數(shù)據(jù), 將其封裝成Person類的對(duì)象后, 并添加到ListBuffer中.
- 對(duì)第4步獲取到的數(shù)據(jù)進(jìn)行排序操作, 并將其轉(zhuǎn)換成List列表.
- 按照指定格式, 通過BufferWriter將排序后的數(shù)據(jù)寫入到目的地文件中(./data/stu.txt)
- 關(guān)閉流對(duì)象.
參考代碼
object ClassDemo08 { //1. 定義樣例類Person, 屬性: 姓名, 語文成績(jī), 數(shù)學(xué)成績(jī), 英語成績(jī), 且該類中有一個(gè)獲取總成績(jī)的方法. case class Student(name:String, chinese:Int, math:Int, english:Int) { def getSum() = chinese + math + english } def main(args: Array[String]): Unit = { //2. 獲取數(shù)據(jù)源文件對(duì)象. val source = Source.fromFile("./data/student.txt") //3. 讀取指定文件(./data/student.txt)中所有的數(shù)據(jù), 并將其封裝到List列表中. var studentList: Iterator[List[String]] = source.getLines().map(_.split(" ")).map(_.toList) //4. 定義可變的列表ListBuffer[Student], 用來記錄所有學(xué)生的信息. val list = new ListBuffer[Student]() //5. 遍歷第二步獲取到的數(shù)據(jù), 將其封裝成Person類的對(duì)象后, 并添加到ListBuffer中. for(s <- studentList) {list += Student(s(0), s(1).toInt, s(2).toInt, s(3).toInt)} //6. 對(duì)第5步獲取到的數(shù)據(jù)進(jìn)行排序操作, 并將其轉(zhuǎn)換成List列表. val sortList = list.sortBy(_.getSum()).reverse.toList //7. 按照指定格式, 通過BufferWriter將排序后的數(shù)據(jù)寫入到目的地文件(./data/stu.txt) val bw = new BufferedWriter(new FileWriter("./data/stu.txt")) for(s <- sortList) bw.write(s"${s.name} ${s.chinese} ${s.math} ${s.english}${s.getSum()}\r\n") //8. 關(guān)閉流對(duì)象 bw.close() } }
到此這篇關(guān)于Scala文件操作示例代碼講解的文章就介紹到這了,更多相關(guān)Scala文件操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IntelliJ IDEA配置Tomcat(完整版圖文教程)
這篇文章主要介紹了IntelliJ IDEA配置Tomcat(完整版圖文教程),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05springboot中使用mybatisplus自帶插件實(shí)現(xiàn)分頁的示例代碼
這篇文章主要介紹了springboot中使用mybatisplus自帶插件實(shí)現(xiàn)分頁,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09SpringMVC核心DispatcherServlet處理流程分步詳解
這篇文章主要介紹了SpringMVC核心之中央調(diào)度器DispatcherServlet的相關(guān)知識(shí),包括SpringMVC請(qǐng)求處理過程及SrpingMVC容器和spring IOC容器關(guān)系,需要的朋友可以參考下2023-04-04java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果,圖片旋轉(zhuǎn)的靈活運(yùn)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01SpringBoot多數(shù)據(jù)源配置的全過程記錄
在用SpringBoot開發(fā)項(xiàng)目時(shí),隨著業(yè)務(wù)量的擴(kuò)大,我們通常會(huì)進(jìn)行數(shù)據(jù)庫(kù)拆分或是引入其他數(shù)據(jù)庫(kù),從而我們需要配置多個(gè)數(shù)據(jù)源,下面這篇文章主要給大家介紹了關(guān)于SpringBoot多數(shù)據(jù)源配置的相關(guān)資料,需要的朋友可以參考下2021-11-11SpringMVC 文件上傳配置,多文件上傳,使用的MultipartFile的實(shí)例
本篇文章主要介紹了SpringMVC 文件上傳配置,詳解介紹了如何使用SpringMVC進(jìn)行表單上的文件上傳以及多個(gè)文件同時(shí)上傳的步驟,有興趣的可以了解一下。2016-12-12springboot+rabbitmq實(shí)現(xiàn)智能家居實(shí)例詳解
這篇文章主要為大家介紹了springboot+rabbitmq實(shí)現(xiàn)智能家居的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Java如何將json字符串與實(shí)體類互相轉(zhuǎn)換
在我們調(diào)用三方平臺(tái)接口時(shí),經(jīng)常需要將我們封裝的實(shí)體類轉(zhuǎn)換為json作為傳參,下面這篇文章主要給大家介紹了關(guān)于Java如何將json字符串與實(shí)體類互相轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下2023-11-11