Spark 的数据读取及数据保存可以从两个维度来作区分:文件格式以及文件系统。
文件格式分为:Text 文件、Json 文件、Csv 文件、Sequence 文件以及 Object 文件;
文件系统分为:本地文件系统、HDFS、HBASE 以及数据库。

Spark 对很多种文件格式的读取和保存方式都很简单。

从诸如文本文件的非结构化的文件,到诸如 JSON 格式的半结构化的文件,再到诸如 SequenceFile 这样的结构化的文件,Spark都可以支持.

spark 读写 sqlserver spark 读写csv文件格式_sequence

4.1.1 文本 文件

1)数据读取:textFile(String) 
scala> val hdfsFile = sc.textFile("hdfs://hadoop102:9000/fruit.txt")
hdfsFile: org.apache.spark.rdd.RDD[String] = hdfs://hadoop102:9000/fruit.txt MapPartitionsRDD[21] at textFile at <console>:24

2)数据保存: saveAsTextFile(String)
scala> hdfsFile.saveAsTextFile("/fruitOut")

4.1.2 Json 文件

如果 JSON 文件中每一行就是一个 JSON 记录,那么可以通过将 JSON 文件当做文本
文件来读取,然后利用相关的 JSON 库对每一条数据进行 JSON 解析。

注意:使用 RDD 读取 JSON 文件处理很复杂,同时 SparkSQL 集成了很好的处理
JSON 文件的方式,所以应用中多是采用 SparkSQL 处理 JSON 文件。

(1)导入解析 json 所需的包 
scala> import scala.util.parsing.json.JSON

2)上传 json 文件到 HDFS
[felix@hadoop102 spark]$ hadoop fs -put ./examples/src/main/resources/people.json /
 
(3)读取文件
scala> val json = sc.textFile("/people.json")
json: org.apache.spark.rdd.RDD[String] = /people.json MapPartitionsRDD[8] at textFile at <console>:24
 
(4)解析 json 数据
scala> val result = json.map(JSON.parseFull)
result: org.apache.spark.rdd.RDD[Option[Any]] = MapPartitionsRDD[10] at map at <console>:27

(5)打印
scala> result.collect
res11: Array[Option[Any]] = Array(Some(Map(name -> Michael)), Some(Map(name -> Andy, age -> 30.0)), Some(Map(name -> Justin, age -> 19.0)))

SparkSQL处理json文件:

在 Scala 中使用 Spark SQL 读取 JSON 数据
     val tweets = hiveCtx.jsonFile("tweets.json")
     tweets.registerTempTable("tweets")
     val results = hiveCtx.sql("SELECT user.name, text FROM tweets")

4.1.3 Sequence 文件

SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对而设计的一种平面
文件(Flat File)。Spark 有专门用来读取 SequenceFile 的接口。在 SparkContext 中,可以
调用 sequenceFile keyClass, valueClass。
注意:SequenceFile 文件只针对 PairRDD

(1)创建一个 RDD
scala> val rdd = sc.parallelize(Array((1,2),(3,4),(5,6)))
rdd: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[13] at parallelize at <console>:24

(2)将 RDD 保存为 Sequence 文件
scala> rdd.saveAsSequenceFile("file:///opt/module/spark/seqFile")

(3)读取 Sequence 文件 
scala> val seq = sc.sequenceFile[Int,Int]("file:///opt/module/spark/seqFile")
seq: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[18] at sequenceFile at <console>:24
 
(4)打印读取后的 Sequence 文件
scala> seq.collect
res14: Array[(Int, Int)] = Array((1,2), (3,4), (5,6))

4.1.4 对象文件 (objectFile)

对象文件是将对象序列化后保存的文件,采用 Java 的序列化机制。可以通过
objectFilek,v 函数接收一个路径,读取对象文件,返回对应的 RDD,也可以通过调
用 saveAsObjectFile() 实现对对象文件的输出。因为是序列化所以要指定类型。

(1)创建一个 RDD
scala> val rdd = sc.parallelize(Array(1,2,3,4))
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[19] at parallelize at <console>:24
 
(2)将 RDD 保存为 Object 文件 
scala> rdd.saveAsObjectFile("file:///opt/module/spark/objectFile")

(3)读取 Object 文件 
scala> val objFile = sc.objectFile[(Int)]("file:///opt/module/spark/objectFile")
objFile: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[31] at objectFile at <console>:24

(4)打印读取后的 Sequence 文件 
scala> objFile.collect
res19: Array[Int] = Array(1, 2, 3, 4)

4.1.5 逗号分隔值(CSV)与制表符分割值(TSV)

  • 读取CSV
  • 读取CSV/TSV数据和读取JSON数据相似,都需要先把文件当做普通文本文件来读取数据,再对数据进行处理。由于格式标准的缺失,同一个库的不同版本有时也会用不同的方式处理输入数据。
  • 如果你的CSV的所有数据字段均没有包含换行符,你也可以使用textFile()读取并解析数据
import Java.io.StringReader
import au.com.bytecode.opencsv.CSVReader
...
val input = sc.textFile(inputFile)
val result = input.map{line => 
	val reader = new CSVReader(new StringReader(line));
	reader.readNext();
 }
如果在字段中嵌有换行符,就需要完整读入每个文件,然后解析。

case class Person(name: String,favoriteAnimal:String)
 
val input = sc.wholeTextFiles(inputFile)
val result = input.flatMap{case (_,txt) =>
  val reader = new CSVReader(new StringReader(txt));
  reader.readAll().map(x => Person(x(0),x(1)))
}
  • 保存CSV

写出CSV/TSV数据很简单,可以通过重用输出编码器来加速

val inputRDD = sc.parallelize(List(Data("index", "title", "content")))
    inputRDD.map(data => List(data.index, data.title, data.content).toArray)
      .mapPartitions { data =>
        val stringWriter = new StringWriter();
        val csvWriter = new CSVWriter(stringWriter);
        csvWriter.writeAll(data.toList)
        Iterator(stringWriter.toString)
      }.saveAsTextFile("/home/common/coding/coding/Scala/word-count/sample_map_out")

上述的例子中只能在我们知道所有要输出的字段时使用,然而如果一些字段名是在运行时由用户输入决定的,就要使用别的方法了,最简单的方法是遍历所有的数据,提取不同的键,然后分别输出。