可以创建先压缩文件然后加密它们的新编解码器。这个想法是在写入文件系统之前用CipherOutputStream 包装编解码器的输出流。
import java.io.{IOException, OutputStream}
import javax.crypto.{Cipher, CipherOutputStream}
import javax.crypto.spec.SecretKeySpec
import org.apache.hadoop.io.compress._
class GzipEncryptionCodec extends GzipCodec {
override def getDefaultExtension(): String = ".gz.enc"
@throws[IOException]
override def createOutputStream(out: OutputStream): CompressionOutputStream =
super.createOutputStream(wrapWithCipherStream(out))
@throws[IOException]
override def createOutputStream(out: OutputStream, compressor: Compressor): CompressionOutputStream =
super.createOutputStream(wrapWithCipherStream(out), compressor)
def wrapWithCipherStream(out: OutputStream): OutputStream = {
val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding") //or another algorithm
val secretKey = new SecretKeySpec(
"hello world 1234".getBytes, //this is not a secure password!
"AES")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
return new CipherOutputStream(out, cipher)
}
}
在编写 csv 文件时,可以使用此编解码器:
df.write
.option("codec","GzipEncryptionCodec")
.mode(SaveMode.Overwrite).csv("encryped_csv")
并且输出文件将被加密并得到后缀.gz.enc。
此编解码器仅加密数据,无法解密。关于为什么更改编解码器以读取比写入更困难的一些背景知识可以在here 找到。
相反,可以使用简单的 Scala 程序读取和解密文件:
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.io.FileInputStream
import java.util.zip.GZIPInputStream
import javax.crypto.CipherInputStream
val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
val secretKey = new SecretKeySpec("hello world 1234".getBytes(), "AES")
cipher.init(Cipher.DECRYPT_MODE, secretKey)
val files = new File("encryped_csv").listFiles.filter(_.getName().endsWith(".gz.enc")).toList
files.foreach(f => {
val dec = new CipherInputStream(new FileInputStream(f), cipher)
val gz = new GZIPInputStream(dec)
val result = scala.io.Source.fromInputStream(gz).mkString
println(f.getName)
println(result)
})