Help us shape the future of Go! Take the 2026 Go Developer Survey

rar

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 18 Imported by: 0

README

go-rar

Pure Go reader and writer for RAR 2.9-4.x archives. It stores files without compression, with an API that mirrors archive/zip, so zip.NewWriter can often become rar.NewWriter.

CBR pages are already-compressed images, so compression would gain little, and RAR4 is read by far more readers than RAR5.

Install

go get github.com/elboletaire/go-rar

Usage

w := rar.NewWriter(f) // f is an *os.File for chapter-01.cbr
for i, page := range pages {
	fw, err := w.Create(fmt.Sprintf("%03d.jpg", i+1))
	if err != nil {
		log.Fatal(err)
	}
	if _, err := fw.Write(page); err != nil {
		log.Fatal(err)
	}
}
if err := w.Close(); err != nil {
	log.Fatal(err)
}

Reading

r, err := rar.OpenReader("chapter-01.cbr")
if err != nil {
	log.Fatal(err)
}
defer r.Close()
for _, f := range r.File {
	fmt.Println(f.Name, f.UnpackedSize)
}
page, err := fs.ReadFile(r, "001.jpg") // checks the CRC32 at EOF
if err != nil {
	log.Fatal(err)
}
fmt.Println(len(page))

Limitations

  • Writing: no compression, encryption, multi-volume, solid archives or RAR5. Each entry is buffered in memory until the next Create or Close.
  • Reading: compressed entries are listed but Open returns ErrAlgorithm. Encrypted, split and RAR5 archives are rejected. The marker must be at offset 0, so SFX archives are not supported.

RAR and WinRAR are trademarks of RARLAB; this project is not affiliated with RARLAB.

MIT licensed, see LICENSE.

Documentation

Overview

Package rar reads and writes RAR 2.9-4.x archives using only the Store method. Its API follows archive/zip, so code that uses zip.NewWriter can switch to NewWriter with few changes.

Index

Examples

Constants

View Source
const (
	HostMSDOS uint8 = 0
	HostWin32 uint8 = 2
	HostUnix  uint8 = 3
	HostMacOS uint8 = 4
	HostBeOS  uint8 = 5
)

Host operating systems, as stored in FileHeader.HostOS.

View Source
const Store uint8 = 0x30

Store is the RAR method for uncompressed data.

Variables

View Source
var (
	ErrFormat       = errors.New("rar: not a valid rar file")
	ErrAlgorithm    = errors.New("rar: unsupported compression algorithm")
	ErrChecksum     = errors.New("rar: checksum error")
	ErrUnsupported  = errors.New("rar: unsupported archive feature")
	ErrInsecurePath = errors.New("rar: insecure file path")
)

Errors returned by this package.

Functions

This section is empty.

Types

type File added in v0.2.0

type File struct {
	FileHeader
	// contains filtered or unexported fields
}

A File is a single file in a RAR archive. The file information is in the embedded FileHeader. The contents are read with File.Open.

func (*File) DataOffset added in v0.2.0

func (f *File) DataOffset() (offset int64, err error)

DataOffset returns the offset of the file's data, relative to the start of the archive. The header was checked by NewReader, so the error is always nil.

func (*File) Open added in v0.2.0

func (f *File) Open() (io.ReadCloser, error)

Open returns an io.ReadCloser for the File's contents. Reading to EOF checks the size and CRC32, and returns ErrChecksum on a mismatch. Split or encrypted files give ErrUnsupported, and methods other than Store give ErrAlgorithm.

type FileHeader

type FileHeader struct {
	// Name is the name of the file, using "/" as the separator. A trailing
	// "/" marks a directory.
	Name string

	// Modified is the modification time. It is stored as an MS-DOS time with
	// 2s resolution, clamped to the years 1980 through 2107.
	Modified time.Time

	// CRC32 is the IEEE CRC32 of the file data, zero for directories.
	CRC32 uint32

	// PackedSize is the size of the data stored in the archive.
	PackedSize uint64

	// UnpackedSize is the size of the file data.
	UnpackedSize uint64

	// Method is the compression method. Zero means Store.
	Method uint8

	// HostOS is the operating system that wrote the file, one of the Host
	// constants.
	HostOS uint8

	// Attributes holds the host-specific attributes: Win32 attributes, or
	// the Unix st_mode for HostUnix.
	Attributes uint32

	// Flags are the RAR file header flags, such as the large and Unicode
	// bits.
	Flags uint16
}

FileHeader describes a file within a RAR archive.

func FileInfoHeader

func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error)

FileInfoHeader creates a partially populated FileHeader from an fs.FileInfo. The name is the base name, so set Name to the full path when it matters. Directories get a trailing "/".

func (*FileHeader) FileInfo

func (h *FileHeader) FileInfo() fs.FileInfo

FileInfo returns an fs.FileInfo for the FileHeader.

func (*FileHeader) Mode

func (h *FileHeader) Mode() fs.FileMode

Mode returns the permission and type bits of the file. Win32 and DOS attributes map to 0666 for files and 0777 for directories, with the write bits cleared for read-only files. Unix, Mac OS and BeOS attributes are st_mode.

func (*FileHeader) SetMode

func (h *FileHeader) SetMode(mode fs.FileMode)

SetMode sets HostOS to HostWin32 and the Win32 attributes from mode. A mode with no write bits gets the read-only attribute.

type ReadCloser added in v0.2.0

type ReadCloser struct {
	Reader
	// contains filtered or unexported fields
}

A ReadCloser is a Reader that must be closed when no longer needed.

func OpenReader added in v0.2.0

func OpenReader(name string) (*ReadCloser, error)

OpenReader opens the RAR file specified by name and returns a ReadCloser. A file name that is not local, or is a drive path, returns ErrInsecurePath along with the reader, as NewReader does.

func (*ReadCloser) Close added in v0.2.0

func (rc *ReadCloser) Close() error

Close closes the RAR file, rendering it unusable for I/O.

type Reader added in v0.2.0

type Reader struct {
	File []*File
	// contains filtered or unexported fields
}

A Reader serves content from a RAR archive.

Example
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/elboletaire/go-rar"
)

func main() {
	// Create an archive in memory, as ExampleWriter does.
	buf := new(bytes.Buffer)
	w := rar.NewWriter(buf)
	for _, file := range []struct{ Name, Body string }{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
	} {
		f, err := w.Create(file.Name)
		if err != nil {
			log.Fatal(err)
		}
		if _, err := f.Write([]byte(file.Body)); err != nil {
			log.Fatal(err)
		}
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	// Open the archive for reading.
	r, err := rar.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
	if err != nil {
		log.Fatal(err)
	}

	// Iterate through the files in the archive, printing some of their contents.
	for _, f := range r.File {
		fmt.Printf("Contents of %s:\n", f.Name)
		rc, err := f.Open()
		if err != nil {
			log.Fatal(err)
		}
		_, err = io.CopyN(os.Stdout, rc, 68)
		if err != nil && err != io.EOF {
			log.Fatal(err)
		}
		rc.Close()
		fmt.Println()
	}

}
Output:
Contents of readme.txt:
This archive contains some text files.
Contents of gopher.txt:
Gopher names:
George
Geoffrey
Gonzo

func NewReader added in v0.2.0

func NewReader(r io.ReaderAt, size int64) (*Reader, error)

NewReader returns a new Reader reading from r, which is assumed to have the given size in bytes. A file name that is not filepath.IsLocal, or is a drive path, returns the reader along with ErrInsecurePath.

func (*Reader) Open added in v0.2.0

func (r *Reader) Open(name string) (fs.File, error)

Open opens the named file in the RAR archive, using the semantics of fs.FS.Open: paths are always slash separated, with no leading / or ../ elements. Directories that the archive does not list are synthesized.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

A Writer writes a RAR archive to an underlying io.Writer. Each entry is buffered in memory until the next entry starts or the archive is closed, so its header can carry the final size and CRC32.

Example
package main

import (
	"bytes"
	"log"

	"github.com/elboletaire/go-rar"
)

func main() {
	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new RAR archive.
	w := rar.NewWriter(buf)

	// Add some files to the archive.
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling licence.\nWrite more examples."},
	}
	for _, file := range files {
		f, err := w.Create(file.Name)
		if err != nil {
			log.Fatal(err)
		}
		_, err = f.Write([]byte(file.Body))
		if err != nil {
			log.Fatal(err)
		}
	}

	// Make sure to check the error on Close.
	err := w.Close()
	if err != nil {
		log.Fatal(err)
	}
}

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter returns a Writer that writes a RAR archive to w. It writes nothing until the first entry is added or Close is called.

func (*Writer) AddFS

func (w *Writer) AddFS(fsys fs.FS) error

AddFS adds the directories and regular files of fsys to the archive, in lexical order. The root directory is not added. Other file types are an error.

func (*Writer) Close

func (w *Writer) Close() error

Close writes the pending entry and the end block. It does not close the underlying writer. Calling Close again returns an error.

func (*Writer) Create

func (w *Writer) Create(name string) (io.Writer, error)

Create adds a file with the given name to the archive, modified now. It is shorthand for CreateHeader with only Name and Modified set.

func (*Writer) CreateHeader

func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error)

CreateHeader adds an entry described by fh and returns a writer for its data, which is buffered until the next entry or Close. Size, CRC32 and Flags of fh are ignored and computed; a trailing "/" or fs.ModeDir makes a directory.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL