Reading and Writing Binary Files in PySpark: A Comprehensive Guide

Exploring PySpark’s Features for Working with Binary Files

Ahmed Uz Zaman
6 min readApr 14, 2023
Photo by Markus Spiske on Unsplash

Intro

Binary files are computer files that contain binary data, which is data that is stored in a non-text format, composed of 0s and 1s. Binary files can be anything from images, audio files, video files, to executable files.

In the context of PySpark, binary files refer to files that contain serialized data. Serialized data is a representation of data in a format that can be easily transmitted over a network or stored in a file. Serialized data is commonly used in big data applications, where data needs to be stored in a compact format to optimize storage and processing.

PySpark provides support for reading and writing binary files through its binaryFiles method. This method can read a directory of binary files and return an RDD where each element is a tuple containing the file's path and its binary content as a byte string. Similarly, the saveAsBinaryFiles method can write an RDD of binary data to a directory in binary file format.

Examples

Reading binary files:

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("ReadBinaryFileExample")
sc = SparkContext(conf=conf)

# Read a directory of binary files
rdd = sc.binaryFiles("/path/to/binary/files")

# Print the contents of each binary file
def print_content(file_path, content):
print("File: ", file_path)
print("Content: ", content)

rdd.foreach(lambda x: print_content(x[0], x[1]))

In this example, we first create a SparkContext object and then use the binaryFiles method to read a directory of binary files. We then define a function print_content that takes the file path and binary content as input and prints them. Finally, we use the foreach method to apply the print_content function to each element of the RDD.

Writing binary files:

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("WriteBinaryFileExample")
sc = SparkContext(conf=conf)

# Create an RDD of binary data
data = sc.parallelize([(1, b"hello"), (2, b"world")])

# Write the RDD to a directory in binary file format
data.saveAsBinaryFiles("/path/to/output/directory")

In this example, we first create a SparkContext object and then create an RDD of binary data. The RDD contains two elements, where each element is a tuple containing an integer and a binary string. We then use the saveAsBinaryFiles method to write the RDD to a directory in binary file format. Each element of the RDD is saved as a separate binary file with a name that includes the integer value.

Reading and Writing with Parameters

Here are some of the commonly used parameters:

  1. minPartitions: This parameter sets the minimum number of partitions for the binary files to be read or written. It is used to control the level of parallelism for processing the binary files.
  2. use_unicode: This parameter is used to specify whether the binary file should be read or written as Unicode text. If set to True, the binary file will be read or written as Unicode text, otherwise as raw bytes.
  3. compression: This parameter specifies the compression format to be used while reading or writing the binary file. Supported compression formats include gzip, snappy, and bzip2.
  4. bufferSize: This parameter sets the size of the buffer used for reading or writing the binary file. Larger buffer sizes can improve performance, but may require more memory.

Here are examples of how to use these parameters while reading and writing binary files in PySpark:

Reading binary files with parameters:

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("ReadBinaryFileExample")
sc = SparkContext(conf=conf)

# Read a directory of binary files with parameters
rdd = sc.binaryFiles("/path/to/binary/files", minPartitions=2, use_unicode=False, compression="gzip", bufferSize=65536)

# Print the contents of each binary file
def print_content(file_path, content):
print("File: ", file_path)
print("Content: ", content)

rdd.foreach(lambda x: print_content(x[0], x[1]))

In this example, we use the minPartitions, use_unicode, compression, and bufferSize parameters while reading binary files. We set minPartitions to 2 to control the level of parallelism, use_unicode to False to read the binary file as raw bytes, compression to "gzip" to read compressed binary files, and bufferSize to 65536 bytes to set the buffer size.

Writing binary files with parameters:

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("WriteBinaryFileExample")
sc = SparkContext(conf=conf)

# Create an RDD of binary data
data = sc.parallelize([(1, b"hello"), (2, b"world")])

# Write the RDD to a directory in binary file format with parameters
data.saveAsBinaryFiles("/path/to/output/directory", minPartitions=2, use_unicode=False, compression="gzip", bufferSize=65536)

In this example, we use the minPartitions, use_unicode, compression, and bufferSize parameters while writing binary files. We set minPartitions to 2 to control the level of parallelism, use_unicode to False to write the binary file as raw bytes, compression to "gzip" to write compressed binary files, and bufferSize to 65536 bytes to set the buffer size.

Note that the parameters you choose will depend on your specific use case and the properties of your binary files, so you may need to experiment with different values to find the best settings for your application.

Reading multiple binary files:

To read multiple binary files, you can pass a directory path containing the files to the binaryFiles() method. The method returns an RDD where each element is a tuple containing the file path and binary content of a single file.

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("ReadMultipleBinaryFiles")
sc = SparkContext(conf=conf)

# Read multiple binary files
rdd = sc.binaryFiles("/path/to/binary/files/*")

# Print the contents of each binary file
def print_content(file_path, content):
print("File: ", file_path)
print("Content: ", content)

rdd.foreach(lambda x: print_content(x[0], x[1]))

In this example, we use the binaryFiles() method to read all binary files in the directory /path/to/binary/files/. The * wildcard is used to match all files in the directory. The print_content() function is used to print the file path and binary content of each file.

Reading all files in a specific folder:

To read all files in a specific folder, you can use the wholeTextFiles() method. The method returns an RDD where each element is a tuple containing the file path and text content of a single file.

from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName("ReadAllFilesInFolder")
sc = SparkContext(conf=conf)

# Read all files in a folder
rdd = sc.wholeTextFiles("/path/to/folder/*")

# Print the contents of each file
def print_content(file_path, content):
print("File: ", file_path)
print("Content: ", content)

rdd.foreach(lambda x: print_content(x[0], x[1]))

In this example, we use the wholeTextFiles() method to read all files in the directory /path/to/folder/. The * wildcard is used to match all files in the directory. The print_content() function is used to print the file path and text content of each file.

Note that when reading multiple binary files or all files in a folder, PySpark will create a separate partition for each file. This can lead to a large number of partitions, which can negatively impact performance. To address this, you can use the minPartitions parameter when reading the files to control the number of partitions.

Advantages of using PySpark for Reading / Writing Binary Files

Spark provides some unique features for reading and writing binary files, which are:

  1. Efficient processing: Spark’s binary file reader is designed to read large binary files efficiently. It uses Hadoop InputFormat API to split files into multiple partitions, which are processed in parallel, thus providing high throughput for large binary files.
  2. Lazy evaluation: Spark’s binary file reader uses a lazy evaluation mechanism, where it reads data only when it is needed, which helps in optimizing memory usage.
  3. Data serialization: Spark’s binary file reader and writer support a wide range of serialization formats, including Java serialization, Kryo, and Avro. This makes it easy to read and write serialized data in a format that is optimal for storage and processing.
  4. File compression: Spark’s binary file reader and writer support various compression formats, such as gzip, Snappy, and bzip2. This helps in reducing the file size and optimizing storage and processing.
  5. Data partitioning: Spark’s binary file reader and writer support data partitioning, where data is split into multiple partitions and processed in parallel. This helps in optimizing data processing performance, especially for large binary files.

Overall, Spark’s support for reading and writing binary files provides a powerful mechanism for processing large binary files efficiently and effectively.

Conclusion

In this article, we have learned about how to use PySpark Binary files API to read and write data. Then we can use it to perform various Data Transformations, Data Analysis, Data Science, etc. Do check out my other articles on PySpark DataFrame API, SQL Basics, and Built-in Functions. Enjoy Reading.

--

--

Ahmed Uz Zaman

Lead QA Engineer | ETL Test Engineer | PySpark | SQL | AWS | Azure | Improvising Data Quality through innovative technologies | linkedin.com/in/ahmed-uz-zaman/