Imports System.IO
Imports SharpCompress.Archives
Imports SharpCompress.Archives.Zip
Imports SharpCompress.Common
Imports SharpCompress.Readers
Imports SharpCompress.Writers

Namespace Compress
    Public Class Compress
        ''' <summary>
        ''' 压缩文件夹到zip文件
        ''' </summary>
        ''' <param name="dirPath">需要压缩的文件夹</param>
        ''' <param name="zipPath">压缩后的zip文件路径</param>
        Public Shared Sub SaveDirToZip(dirPath As String, zipPath As String)
            Using fileStream As FileStream = File.OpenWrite(zipPath)
                Using archive As ZipArchive = ZipArchive.Create()
                    archive.AddAllFromDirectory(dirPath)
                    archive.SaveTo(fileStream)
                End Using
            End Using
        End Sub


        Public Shared Sub LoadFromZip(dirPath As String, zipPath As String)
            Using fileStream As FileStream = File.OpenRead(zipPath)
                Using reader As IReader = ReaderFactory.Open(fileStream)
                    Dim options As New ExtractionOptions With {.ExtractFullPath = True, .Overwrite = True, .PreserveFileTime = True}

                    While reader.MoveToNextEntry
                        If reader.Entry.IsDirectory = False Then
                            reader.WriteEntryToDirectory(dirPath, options)
                        End If
                    End While
                End Using
            End Using
        End Sub

        ''' <summary>
        ''' 压缩文件至Zip文件
        ''' </summary>
        ''' <param name="filePath">被压缩的文件路径</param>
        ''' <param name="zipFilePath">压缩文件路径</param>
        Public Shared Sub SaveFileToZip(filePath As String, zipFilePath As String)
            If File.Exists(zipFilePath) Then File.Delete(zipFilePath)
            Using tarStream As FileStream = File.OpenWrite(zipFilePath)

                Using writer As IWriter = WriterFactory.Open(tarStream, ArchiveType.Zip, CompressionType.None)
                    writer.Write(Path.GetFileName(filePath), File.OpenRead(filePath), File.GetLastWriteTimeUtc(filePath))
                End Using
            End Using
        End Sub



        ''' <summary>
        ''' 压缩指定文件夹至tar格式文件,不会生成根文件目录
        ''' </summary>
        ''' <param name="tarFilename">压缩文件名</param>
        ''' <param name="sourceDirectory">源文件夹</param>
        Public Shared Sub TarCreateFromStream(tarFilename As String, sourceDirectory As String)
            Dim filesPath As String = sourceDirectory
            Using tarStream As FileStream = File.OpenWrite(tarFilename)
                Using writer As IWriter = WriterFactory.Open(tarStream, ArchiveType.Tar, CompressionType.GZip)
                    writer.WriteAll(filesPath, "*", SearchOption.AllDirectories)
                End Using
            End Using
        End Sub

        ''' <summary>
        ''' 压缩指定文件列表到tar格式文件
        ''' </summary>
        ''' <param name="fileList">文件列表</param>
        ''' <param name="tarFilePath">压缩文件路径</param>
        ''' <param name="dirFullPath">压缩文件所在文件夹路径</param>
        Public Shared Sub TarFiles(fileList As List(Of String), tarFilePath As String, dirFullPath As String)
            If File.Exists(tarFilePath) Then File.Delete(tarFilePath)
            Using tarStream As FileStream = File.OpenWrite(tarFilePath)
                Using writer As IWriter = WriterFactory.Open(tarStream, ArchiveType.Tar, CompressionType.GZip)
                    For i As Integer = 0 To fileList.Count - 1
                        If Right(fileList.Item(i), 1) = "\" OrElse Right(fileList.Item(i), 1) = "/" Then
                            writer.WriteAll($"{dirFullPath}\{fileList.Item(i)}", "*", SearchOption.AllDirectories)
                        Else
                            writer.Write(fileList.Item(i), File.OpenRead($"{dirFullPath}\{fileList.Item(i)}"), File.GetLastWriteTimeUtc($"{dirFullPath}\{fileList.Item(i)}"))
                        End If
                    Next
                End Using
            End Using
            GC.Collect() '回收资源
        End Sub


        ''' <summary>
        ''' 填充文件表,供压缩文件使用
        ''' </summary>
        ''' <param name="fileList">文件列表</param>
        ''' <param name="dir">需要压缩的文件夹</param>
        ''' <param name="prefix">文件前缀</param>
        Public Shared Sub FillFileList(fileList As List(Of String), dir As String, prefix As String)
            For Each fName As String In Directory.GetFiles(dir)
                fileList.Add($"{prefix}/{Path.GetFileName(fName) }")
            Next

            For Each dirName As String In Directory.GetDirectories(dir)
                FillFileList(fileList, dirName, $"{prefix}/{Path.GetFileName(dirName)}")
            Next
        End Sub

        Public Shared Sub TarFiles(fileList As List(Of String), filePathList As List(Of String), tarFileName As String)
            If File.Exists(tarFileName) Then File.Delete(tarFileName)
            Using tarStream As FileStream = File.OpenWrite(tarFileName)
                Using writer As IWriter = WriterFactory.Open(tarStream, ArchiveType.Tar, CompressionType.GZip)
                    For i As Integer = 0 To fileList.Count - 1
                        If Right(fileList.Item(i), 1) = "\" OrElse Right(fileList.Item(i), 1) = "/" Then
                            writer.WriteAll($"{filePathList(i)}", "*", SearchOption.AllDirectories)
                        Else
                            writer.Write(fileList.Item(i), File.OpenRead($"{filePathList(i)}"), File.GetLastWriteTimeUtc($"{filePathList(i)}"))
                        End If
                    Next
                End Using
            End Using
        End Sub

        ''' <summary>
        ''' 解压Tar格式文件夹
        ''' </summary>
        ''' <param name="filePath">文件路径</param>
        ''' <param name="destDirectory">目标文件夹</param>
        Public Shared Sub TarExtractToDirectory(filePath As String, destDirectory As String)
            Using tar As Stream = File.OpenRead(filePath)
                Using reader As IReader = ReaderFactory.Open(tar)
                    While reader.MoveToNextEntry
                        If Not reader.Entry.IsDirectory Then
                            Dim a As New ExtractionOptions With {
                                .ExtractFullPath = True,
                                .Overwrite = True,
                                .PreserveFileTime = True
                            }
                            reader.WriteEntryToDirectory(destDirectory, a)
                        End If
                    End While
                End Using
            End Using
        End Sub
    End Class
End Namespace