Go语言教程之边写边学:数据结构与算法:LZW 数据无损压缩和解压缩
1、LZW算法的基本概念
LZW有三个重要对象:数据流(CharStream)、编码流(String Table)和编译表(String Table)。
(1)编码时,数据流是输入对象 (数据序列),编码流就是输出对象(经过压缩运算的编码数据);
(2)解码时,编码流是输入对象,数据流是输出对象;而编译表是在编码和解码时都需要借助的对象。
2、LZW压缩的基本原理
提取原始文本文件数据中的不同字符,基于这些字符创建一个编译表,然后用编译表中的字符的索引来替代原始数据中的相应字符,减少原始数据大小。注意:此处的编译表是根据原始数据动态创建的,解码时需要从已编码的数据中还原出原来的编译表。
3LZW算法流程
步骤一:开始时词典包含所有可能的根,当前前缀字符串P和 当前字符 均为空;
步骤二:读入新的字符C,与P合并形成字符串P+C;
步骤三:判断P+C是否在字典中
                        如果"是":
                                P = P + C; 
                                返回步骤二;
                        如果"否":
                                输出P的映射;
                                 P = P+C ;
                                把前缀字符串P添加到字典,建立映射;
                                令P = C //(现在的P仅包含一个字符C);
步骤四: 判断码字流中是否还有码字要译
                         如果"是":
                                 返回步骤二;
                         如果"否":
                            把代表当前前缀P的码字输出到码字流;
                            结束。


实现代码:

package main
import "fmt"
 

func compressLZW(testStr string) []int {    
    code := 256
    dictionary := make(map[string]int)
    for i := 0; i < 256; i++ {
        dictionary[string(i)] = i
    }
 
    currChar := ""
    result := make([]int, 0)	
    for _, c := range []byte(testStr) {	
        phrase := currChar + string(c)
        if _, isTrue := dictionary[phrase]; isTrue {		
            currChar = phrase
        } else {
            result = append(result, dictionary[currChar])
            dictionary[phrase] = code
            code++
            currChar = string(c)
        }
    }
    if currChar != "" {
        result = append(result, dictionary[currChar])
    }
    return result
}
 

func decompressLZW(compressed []int) string {    
    code := 256
    dictionary := make(map[int]string)
    for i := 0; i < 256; i++ {
        dictionary[i] = string(i)
    }
 
    currChar := string(compressed[0])
    result := currChar
    for _, element := range compressed[1:] {
        var word string
        if x, ok := dictionary[element]; ok {
            word = x
        } else if element == code {
            word = currChar + currChar[:1]
        } else {
            panic(fmt.Sprintf("Bad compressed element: %d", element))
        }
 
        result += word
        
        dictionary[code] = currChar + word[:1]
        code++
 
        currChar = word
    }
    return result
}
 
func main() {
	fmt.Print("Enter any string :")
	var testStr string
    fmt.Scanln(&testStr)
	
    compressed := compressLZW(testStr)
    fmt.Println("\nAfter Compression :", compressed)
	
    uncompression := decompressLZW(compressed)
    fmt.Println("\nAfter Uncompression :", uncompression)
}

输出:

Enter any string :Australia
After Compression : [65 117 115 116 114 97 108 105 97]

After Uncompression : Australia

C:\golang\example>go run test.go
Enter any string :Germany

After Compression : [71 101 114 109 97 110 121]

After Uncompression : Germany
Go语言教程之边写边学:操作文件和文件夹,压缩和解压缩

允许我们将文件和目录作为实体进行操作的最重要的包是os包。
io包具有读取数据并将其从源传输到字节流的io.Reader接口。io.Writer接口从提供的字节流中读取数据,并将其作为输出写入目标资源。

 

创建一个空文件

package main
 
import (
	"log"
	"os"
)
 
func main() {
	emptyFile, err := os.Create("empty.txt")
	if err != nil {
		log.Fatal(err)
	}
	log.Println(emptyFile)
	emptyFile.Close()
}

输出

2018/08/11 15:46:04 &{0xc042060780}

 

创建目录

package main
 
import (
	"log"
	"os"
)
 
func main() {
	_, err := os.Stat("test")
 
	if os.IsNotExist(err) {
		errDir := os.MkdirAll("test", 0755)
		if errDir != nil {
			log.Fatal(err)
		}
 
	}
}

 

重命名文件

package main
 
import (
	"log"
	"os"
)
 
func main() {
	oldName := "test.txt"
	newName := "testing.txt"
	err := os.Rename(oldName, newName)
	if err != nil {
		log.Fatal(err)
	}
}

 

将文件从一个位置移动到另一个位置

os.Rename()还可以将文件从一个位置移动到另一个位置,同时重命名文件名。

package main
 
import (
	"log"
	"os"
)
 
func main() {
	oldLocation := "/var/www/html/test.txt"
	newLocation := "/var/www/html/src/test.txt"
	err := os.Rename(oldLocation, newLocation)
	if err != nil {
		log.Fatal(err)
	}
}

 

复制文件

package main
 
import (
	"io"
	"log"
	"os"
)
 
func main() {
 
	sourceFile, err := os.Open("/var/www/html/src/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer sourceFile.Close()
 
	// Create new file
	newFile, err := os.Create("/var/www/html/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer newFile.Close()
 
	bytesCopied, err := io.Copy(newFile, sourceFile)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Copied %d bytes.", bytesCopied)
}

输出

2018/08/15 03:43:39 Copied 100 bytes.

 

获取文件的元数据

package main
 
import (
	"fmt"
	"log"
	"os"
)
 
func main() {
	fileStat, err := os.Stat("test.txt")
 
	if err != nil {
		log.Fatal(err)
	}
 
	fmt.Println("File Name:", fileStat.Name())        // Base name of the file
	fmt.Println("Size:", fileStat.Size())             // Length in bytes for regular files
	fmt.Println("Permissions:", fileStat.Mode())      // File mode bits
	fmt.Println("Last Modified:", fileStat.ModTime()) // Last modification time
	fmt.Println("Is Directory: ", fileStat.IsDir())   // Abbreviation for Mode().IsDir()
}

输出

File Name: test.txt
Size: 100
Permissions: -rw-rw-rw-
Last Modified: 2018-08-11 20:19:14.2671925 +0530 IST
Is Directory:  false

 

删除文件

package main
 
import (
	"log"
	"os"
)
 
func main() {
	err := os.Remove("/var/www/html/test.txt")
	if err != nil {
		log.Fatal(err)
	}
}

 

逐个字符读取文本文件

package main
 
import (
	"bufio"
	"fmt"
	"os"
	"strings"
)
 
func main() {
	filename := "test.txt"
 
	filebuffer, err := os.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	inputdata := string(filebuffer)
	data := bufio.NewScanner(strings.NewReader(inputdata))
	data.Split(bufio.ScanRunes)
 
	for data.Scan() {
		fmt.Print(data.Text())
	}
}

 

截断文件内容

操作系统。Truncate()函数会将文件内容减少到第二个参数中传递的 N 个字节。在下面的示例中,如果 test.txt 文件的大小大于 1Kb,那么它将截断剩余的内容。

package main
 
import (
	"log"
	"os"
)
 
func main() {
	err := os.Truncate("test.txt", 1000)
 
	if err != nil {
		log.Fatal(err)
	}
}

 

在文本文件中追加内容

package main
 
import (
	"fmt"
	"os"
)
 
func main() {
	message := "Add this content at end"
	filename := "test.txt"
 
	f, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)
 
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	defer f.Close()
 
	fmt.Fprintf(f, "%s\n", message)
}

 

更改文件权限、所有权和时间戳

package main
 
import (
	"log"
	"os"
	"time"
)
 
func main() {
	_, err := os.Stat("test.txt")
	if err != nil {
		if os.IsNotExist(err) {
			log.Fatal("File does not exist.")
		}
	}
	log.Println("File exist.")
 
	// 修改权限
	err = os.Chmod("test.txt", 0777)
	if err != nil {
		log.Println(err)
	}
 
	// 修改所有权
	err = os.Chown("test.txt", os.Getuid(), os.Getgid())
	if err != nil {
		log.Println(err)
	}
 
	// 修改时间
	addOneDayFromNow := time.Now().Add(24 * time.Hour)
	lastAccessTime := addOneDayFromNow
	lastModifyTime := addOneDayFromNow
	err = os.Chtimes("test.txt", lastAccessTime, lastModifyTime)
	if err != nil {
		log.Println(err)
	}
}

 

将多个文件压缩为ZIP文件

package main
 
import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
)
 
func appendFiles(filename string, zipw *zip.Writer) error {
	file, err := os.Open(filename)
	if err != nil {
		return fmt.Errorf("Failed to open %s: %s", filename, err)
	}
	defer file.Close()
 
	wr, err := zipw.Create(filename)
	if err != nil {
		msg := "Failed to create entry for %s in zip file: %s"
		return fmt.Errorf(msg, filename, err)
	}
 
	if _, err := io.Copy(wr, file); err != nil {
		return fmt.Errorf("Failed to write %s to zip: %s", filename, err)
	}
 
	return nil
}
 
func main() {
	flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
	file, err := os.OpenFile("test.zip", flags, 0644)
	if err != nil {
		log.Fatalf("Failed to open zip for writing: %s", err)
	}
	defer file.Close()
 
	var files = []string{"test1.txt", "test2.txt", "test3.txt"}
 
	zipw := zip.NewWriter(file)
	defer zipw.Close()
 
	for _, filename := range files {
		if err := appendFiles(filename, zipw); err != nil {
			log.Fatalf("Failed to add file %s to zip: %s", filename, err)
		}
	}
}

 

读取ZIP文件内的文件列表

package main
 
import (
	"archive/zip"
	"fmt"
	"log"
	"os"
)
 
func listFiles(file *zip.File) error {
	fileread, err := file.Open()
	if err != nil {
		msg := "Failed to open zip %s for reading: %s"
		return fmt.Errorf(msg, file.Name, err)
	}
	defer fileread.Close()
 
	fmt.Fprintf(os.Stdout, "%s:", file.Name)
 
	if err != nil {
		msg := "Failed to read zip %s for reading: %s"
		return fmt.Errorf(msg, file.Name, err)
	}
 
	fmt.Println()
 
	return nil
}
 
func main() {
	read, err := zip.OpenReader("test.zip")
	if err != nil {
		msg := "Failed to open: %s"
		log.Fatalf(msg, err)
	}
	defer read.Close()
 
	for _, file := range read.File {
		if err := listFiles(file); err != nil {
			log.Fatalf("Failed to read %s from zip: %s", file.Name, err)
		}
	}
}

 

提取或解压缩

package main
 
import (
	"archive/zip"
	"io"
	"log"
	"os"
	"path/filepath"
)
 
func main() {
	zipReader, _ := zip.OpenReader("test.zip")
	for _, file := range zipReader.Reader.File {
 
		zippedFile, err := file.Open()
		if err != nil {
			log.Fatal(err)
		}
		defer zippedFile.Close()
 
		targetDir := "./"
		extractedFilePath := filepath.Join(
			targetDir,
			file.Name,
		)
 
		if file.FileInfo().IsDir() {
			log.Println("Directory Created:", extractedFilePath)
			os.MkdirAll(extractedFilePath, file.Mode())
		} else {
			log.Println("File extracted:", file.Name)
 
			outputFile, err := os.OpenFile(
				extractedFilePath,
				os.O_WRONLY|os.O_CREATE|os.O_TRUNC,
				file.Mode(),
			)
			if err != nil {
				log.Fatal(err)
			}
			defer outputFile.Close()
 
			_, err = io.Copy(outputFile, zippedFile)
			if err != nil {
				log.Fatal(err)
			}
		}
	}
}
  • 当前日期:
  • 北京时间:
  • 时间戳:
  • 今年的第:18周
  • 我的 IP:18.116.118.216
农历
五行
冲煞
彭祖
方位
吉神
凶神
极简任务管理 help
+ 0 0 0
Task Idea Collect