CSharp tar类型文件压缩与解压

最近闲暇时间开始写点通用基础类在写到tar类型文件压缩与解压时遇到点问题

压缩用的类库我是下载的 SharpZipLib_0860版本

先上代码

加压核心

		/// <summary>
		/// 内部文件及文件夹压缩方法
		/// </summary>
		/// <param name="paths">被压缩的文件及文件夹路径</param>
		/// <param name="outputStream">tar压缩文件流</param>
		/// <param name="basePath">压缩文件流基于的根路径</param>
		private void AddCompressFileAndFolders(string[] paths, TarOutputStream outputStream, string basePath, int compression)
		{
			try
			{
				foreach (string path in paths)
				{
					TarEntry entry = null;
					if (FolderProvider.IsFolder(path))
					{
						if (string.IsNullOrEmpty(basePath))
							basePath = FolderProvider.GetSuperFolderPath(path);

						//is directory
						string[] subFileAndFolders = FolderProvider.GetAllContainsFileAndFolderPaths(path);
						TarHeader header = new TarHeader();
						header.Name = path.Replace(basePath + "\", string.Empty) + "\";
						header.Mode = compression;
						entry = new TarEntry(header);
						if (subFileAndFolders.Length == 0)
						{
							outputStream.PutNextEntry(entry);
							outputStream.CloseEntry();
						}
						/*当前路径为子路径的父路径*/
						AddCompressFileAndFolders(subFileAndFolders, outputStream, basePath, compression);
					}
					else
					{
						//is file
						using (FileStream file = System.IO.File.OpenRead(path))
						{
							string filePath = path;
							if (!string.IsNullOrEmpty(basePath))
							{
								filePath = path.Replace(basePath + "\", string.Empty);
							}
							else
							{
								filePath = Path.GetFileName(path);
							}

							byte[] buffer = new byte[1024 * 1024 * 4];
							int size = 1;
							TarHeader header = new TarHeader();
							header.Name = filePath;
							header.ModTime = DateTime.Now;
							header.Size = file.Length;
							entry = new TarEntry(header);
							outputStream.PutNextEntry(entry);

							while (size > 0)
							{
								size = file.Read(buffer, 0, buffer.Length);
								if (size == 0)
									break;
								outputStream.Write(buffer, 0, size);
							}
							outputStream.CloseEntry();
						}
					}
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}


解压核心

		/// <summary>
		/// 功能:解压tar格式的文件。
		/// </summary>
		/// <param name="zipFilePath">压缩文件路径</param>
		/// <param name="unZipDir">解压文件存放路径,为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹</param>
		/// <param name="password">密码</param>
		/// <returns>解压是否成功</returns>
		public bool UnCompressFile(string zipFilePath, string unZipDir = null, string password = null)
		{
			if (zipFilePath == string.Empty)
			{
				throw new Exception("压缩文件不能为空!");
			}
			if (!System.IO.File.Exists(zipFilePath))
			{
				throw new Exception("压缩文件不存在!");
			}
			//解压文件夹为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹
			if (string.IsNullOrEmpty(unZipDir))
				unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath));
			if (!unZipDir.EndsWith("\"))
				unZipDir += "\";
			if (!Directory.Exists(unZipDir))
				FolderProvider.CreateDirectory(unZipDir);

			try
			{
				using (TarInputStream input = new TarInputStream(System.IO.File.OpenRead(zipFilePath)))
				{
					//if (!string.IsNullOrEmpty(password)) input.Password = password;

					TarEntry theEntry;
					while ((theEntry = input.GetNextEntry()) != null)
					{
						string directoryName = Path.GetDirectoryName(theEntry.Name);
						//string fileName = Path.GetFileName(Encoding.UTF8.GetString(theEntry.Name));
						string fileName = Path.GetFileName(theEntry.Name);
						if (directoryName.Length > 0)
						{
							Directory.CreateDirectory(unZipDir + directoryName);
						}
						if (!directoryName.EndsWith("\"))
							directoryName += "\";
						if (fileName != String.Empty)
						{
							// Because the uncompressed size of the file is unknown, 
							// we are using an arbitrary buffer size.
							byte[] buffer = new byte[1024 * 1024 * 4];
							int size = buffer.Length;

							using (FileStream streamWriter = System.IO.File.Create(unZipDir + theEntry.Name))
							{
								while (size > 0)
								{
									size = input.Read(buffer, 0, buffer.Length);
									if (size == 0) break;
									streamWriter.Write(buffer, 0, size);
								}
							}
						}
					}//while
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			return true;
		}//解压结束


遇到的问题是

1,中文乱码,

2 压缩文件中的空文件夹下多了个不知道是没有没名称的文件夹还是没有名称及后缀名的文件但是用解压方法解压或是解压工具解压后确实是空文件夹

中文乱码的解决:

根据问题应该是在字符与byte转换时没有指点Encoding造成的, 下载SharpZipLib_0860_SourceSamples.zip,源码查看

先调整加压函数,修个TarHeader文件里的下面的函数,下面是修正后的

		/// <summary>
		/// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
		/// </summary>
		/// <param name="name">The name to add</param>
		/// <param name="nameOffset">The offset of the first character</param>
		/// <param name="buffer">The buffer to add to</param>
		/// <param name="bufferOffset">The index of the first byte to add</param>
		/// <param name="length">The number of characters/bytes to add</param>
		/// <returns>The next free index in the <paramref name="buffer"/></returns>
		public static int GetNameBytes(string name, int nameOffset, byte[] buffer, int bufferOffset, int length)
		{
			if (name == null)
			{
				throw new ArgumentNullException("name");
			}

			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}

			int i;

			///解决tar压缩中文乱码问题
			byte[] arrName = Encoding.GetEncoding(Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage).GetBytes(name);
			for (i = 0; i < length - 1 && nameOffset + i < arrName.Length; ++i)
			{
				buffer[bufferOffset + i] = (byte)arrName[nameOffset + i];
			}

			for (; i < length; ++i)
			{
				buffer[bufferOffset + i] = 0;
			}

			return bufferOffset + length;
		}


编译后调用,运行单元测试,压缩文件中中文显示正常,运行解压测试,解压后依旧乱码,

继续调整TarHeader文件中的函数,调整后如下:

		/// <summary>
		/// Parse a name from a header buffer.
		/// </summary>
		/// <param name="header">
		/// The header buffer from which to parse.
		/// </param>
		/// <param name="offset">
		/// The offset into the buffer from which to parse.
		/// </param>
		/// <param name="length">
		/// The number of header bytes to parse.
		/// </param>
		/// <returns>
		/// The name parsed.
		/// </returns>
		static public StringBuilder ParseName(byte[] header, int offset, int length)
		{
			if (header == null)
			{
				throw new ArgumentNullException("header");
			}

			if (offset < 0)
			{
#if NETCF_1_0
				throw new ArgumentOutOfRangeException("offset");
#else
				throw new ArgumentOutOfRangeException("offset", "Cannot be less than zero");
#endif
			}

			if (length < 0)
			{
#if NETCF_1_0
				throw new ArgumentOutOfRangeException("length");
#else
				throw new ArgumentOutOfRangeException("length", "Cannot be less than zero");
#endif
			}

			if (offset + length > header.Length)
			{
				throw new ArgumentException("Exceeds header size", "length");
			}

			StringBuilder result = new StringBuilder(length);
			List<byte> temp = new List<byte>();
			for (int i = offset; i < offset + length; ++i)
			{
				if (header[i] == 0)
				{
					break;
				}
				//result.Append((char)header[i]);
				temp.Add(header[i]);
			}

			result.Append(Encoding.GetEncoding(Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage).GetString(temp.ToArray()));

			return result;
		}


之前说的第二个问题还没解决,希望有哪位大侠解决了告诉我一下,多谢



原文地址:https://www.cnblogs.com/james1207/p/3290204.html