{
单元名:跨平台的TCP客户端库封装
作者:5bug
网站:http://www.5bug.wang
}
unit uCPTcpClient;
interface
uses System.Classes, System.SysUtils, IdTCPClient, IdGlobal;
type
TOnRevDataEvent = procedure(const pData: Pointer; const pSize: Cardinal) of object;
TCPTcpClient = class
private
FConnected: Boolean;
FHost: string;
FPort: Integer;
FOnRevDataEvent: TOnRevDataEvent;
FOnDisconnectEvent: TNotifyEvent;
type
TTcpThreadType = (tt_Send, tt_Recv, tt_Handle);
TCPTcpThread = class(TThread)
private
FOnExecuteProc: TProc;
protected
procedure Execute; override;
public
property OnExecuteProc: TProc read FOnExecuteProc write FOnExecuteProc;
end;
TTcpDataRecord = class(TMemoryStream);
protected
FTCPClient: TIdTCPClient;
FSendDataList: TThreadList;
FRecvDataList: TThreadList;
FCahceDataList: TThreadList;
FTcpThread: array [TTcpThreadType] of TCPTcpThread;
procedure InitThread;
procedure FreeThread;
procedure ExcuteSendProc;
procedure ExcuteRecvProc;
procedure ExcuteHandleProc;
procedure ExcuteDisconnect;
procedure ClearData;
function PushToSendCahce(const AData: Pointer; const ASize: NativeInt): Boolean;
public
constructor Create();
destructor Destroy; override;
procedure InitHostAddr(const AHost: string; const APort: Integer);
function TryConnect: Boolean;
procedure DisConnect;
function Send(const AData: Pointer; const ASize: NativeInt): Boolean;
property Connected: Boolean read FConnected;
property Host: string read FHost;
property Port: Integer read FPort;
property OnRevDataEvent: TOnRevDataEvent read FOnRevDataEvent write FOnRevDataEvent;
property OnDisconnectEvent: TNotifyEvent read FOnDisconnectEvent write FOnDisconnectEvent;
end;
implementation
uses uLogSystem;
{ TCPTcpClient }
procedure TCPTcpClient.ClearData;
var
I: Integer;
ADataRecord: TTcpDataRecord;
begin
with FSendDataList.LockList do
try
for I := to Count - do
begin
ADataRecord := Items[I];
FreeAndNil(ADataRecord);
end;
Clear;
finally
FSendDataList.UnlockList;
end;
with FRecvDataList.LockList do
try
for I := to Count - do
begin
ADataRecord := Items[I];
FreeAndNil(ADataRecord);
end;
Clear;
finally
FRecvDataList.UnlockList;
end;
with FCahceDataList.LockList do
try
for I := to Count - do
begin
ADataRecord := Items[I];
FreeAndNil(ADataRecord);
end;
Clear;
finally
FCahceDataList.UnlockList;
end;
end;
constructor TCPTcpClient.Create;
begin
FTCPClient := TIdTCPClient.Create(nil);
FTCPClient.ConnectTimeout := ;
FTCPClient.ReadTimeout := ;
InitThread;
end;
destructor TCPTcpClient.Destroy;
begin
FreeThread;
FTCPClient.Free;
inherited;
end;
procedure TCPTcpClient.DisConnect;
begin
ExcuteDisconnect;
end;
procedure TCPTcpClient.ExcuteDisconnect;
begin
FConnected := False;
FTCPClient.DisConnect;
if MainThreadID = CurrentThreadId then
begin
if Assigned(FOnDisconnectEvent) then
FOnDisconnectEvent(Self);
end
else
begin
TThread.Synchronize(FTcpThread[tt_Recv],
procedure
begin
if Assigned(FOnDisconnectEvent) then
FOnDisconnectEvent(Self);
end);
end;
end;
procedure TCPTcpClient.ExcuteHandleProc;
var
I: Integer;
ADataRecord: TTcpDataRecord;
begin
// 不要长时间锁住收数据的列队
with FRecvDataList.LockList do
try
while Count > do
begin
ADataRecord := Items[];
FCahceDataList.Add(ADataRecord);
Delete();
end;
finally
FRecvDataList.UnlockList;
end;
with FCahceDataList.LockList do
try
while Count > do
begin
ADataRecord := Items[];
Delete();
TThread.Synchronize(FTcpThread[tt_Handle],
procedure
begin
if Assigned(FOnRevDataEvent) then
FOnRevDataEvent(ADataRecord.Memory, ADataRecord.Size);
FreeAndNil(ADataRecord);
end);
end;
finally
FCahceDataList.UnlockList;
end;
end;
procedure TCPTcpClient.ExcuteRecvProc;
var
ADataRecord: TTcpDataRecord;
ADataSize: Integer;
begin
if FConnected then
begin
try
FTCPClient.Socket.CheckForDataOnSource();
ADataSize := FTCPClient.IOHandler.InputBuffer.Size;
if ADataSize > then
begin
ADataRecord := TTcpDataRecord.Create;
with FRecvDataList.LockList do
try
Add(ADataRecord);
finally
FRecvDataList.UnlockList;
end;
FTCPClient.Socket.ReadStream(ADataRecord, ADataSize);
end;
FTCPClient.Socket.CheckForDisconnect(False, True);
except
ExcuteDisconnect;
end;
end;
Sleep();
end;
function TCPTcpClient.PushToSendCahce(const AData: Pointer; const ASize: NativeInt): Boolean;
var
ADataRecord: TTcpDataRecord;
begin
Result := False;
if FConnected then
begin
ADataRecord := TTcpDataRecord.Create;
ADataRecord.Write(AData^, ASize);
with FSendDataList.LockList do
try
Add(ADataRecord);
finally
FSendDataList.UnlockList;
end;
Result := True;
end;
end;
procedure TCPTcpClient.ExcuteSendProc;
var
ADataRecord: TTcpDataRecord;
begin
if FConnected then
begin
ADataRecord := nil;
with FSendDataList.LockList do
try
if Count > then
begin
ADataRecord := Items[];
Delete();
end;
finally
FSendDataList.UnlockList;
end;
if ADataRecord <> nil then
begin
FTCPClient.IOHandler.Write(ADataRecord);
FreeAndNil(ADataRecord);
end;
end;
Sleep();
end;
procedure TCPTcpClient.InitThread;
var
I: Integer;
AThreadType: TTcpThreadType;
begin
FSendDataList := TThreadList.Create;
FRecvDataList := TThreadList.Create;
FCahceDataList := TThreadList.Create;
for AThreadType := Low(TTcpThreadType) to High(TTcpThreadType) do
begin
FTcpThread[AThreadType] := TCPTcpThread.Create(True);
FTcpThread[AThreadType].FreeOnTerminate := False;
case AThreadType of
tt_Send:
FTcpThread[AThreadType].OnExecuteProc := ExcuteSendProc;
tt_Recv:
FTcpThread[AThreadType].OnExecuteProc := ExcuteRecvProc;
tt_Handle:
FTcpThread[AThreadType].OnExecuteProc := ExcuteHandleProc;
end;
FTcpThread[AThreadType].Start;
end;
end;
procedure TCPTcpClient.FreeThread;
var
I: Integer;
AThreadType: TTcpThreadType;
begin
for AThreadType := Low(TTcpThreadType) to High(TTcpThreadType) do
begin
if FTcpThread[AThreadType].Suspended then
{$WARN SYMBOL_DEPRECATED OFF}
FTcpThread[AThreadType].Resume;
{$WARN SYMBOL_DEPRECATED ON}
FTcpThread[AThreadType].Terminate;
FTcpThread[AThreadType].WaitFor;
FTcpThread[AThreadType].Free;
FTcpThread[AThreadType] := nil;
end;
ClearData;
FSendDataList.Free;
FRecvDataList.Free;
FCahceDataList.Free;
end;
procedure TCPTcpClient.InitHostAddr(const AHost: string; const APort: Integer);
begin
FHost := AHost;
FPort := APort;
end;
function TCPTcpClient.Send(const AData: Pointer; const ASize: NativeInt): Boolean;
begin
Result := PushToSendCahce(AData, ASize);
end;
function TCPTcpClient.TryConnect: Boolean;
begin
try
FTCPClient.Host := FHost;
FTCPClient.Port := FPort;
FTCPClient.Connect;
FConnected := True;
except
on E: Exception do
begin
FConnected := False;
end;
end;
Result := FConnected;
end;
{ TCPTcpClient.TCPTcpThread }
procedure TCPTcpClient.TCPTcpThread.Execute;
begin
inherited;
while not Terminated do
begin
if Assigned(FOnExecuteProc) then
FOnExecuteProc;
end;
end;
end.
unit uCPHttpClient;
interface
uses System.Classes, System.SysUtils, System.Net.HttpClient, uXGDataList;
const
V_HttpResponse_Success = ;
V_HttpResponse_ConnectFail = ;
V_HttpResponse_ReadTimeOut = ;
type
TCPHttpType = (ht_Get, ht_Post, ht_Put);
TCPHttpResponse = record
StatusCode: Integer;
HttpData: string;
ErrorMsg: string;
end;
TOnResponseEvent = reference to procedure(const AHttpResponse: TCPHttpResponse);
TCPHttpClient = class
private type
TCPWorkState = (ws_Wait, ws_Work);
TCPHttpThread = class(TThread)
private
FOnExecuteProc: TProc;
protected
procedure Execute; override;
public
property OnExecuteProc: TProc read FOnExecuteProc write FOnExecuteProc;
end;
TCPHttpItem = class(TObject)
private
procedure DoHttpReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean);
function ConvertResponse(const AResponse: IHTTPResponse): TCPHttpResponse; overload;
function ConvertResponse(const AError: string): TCPHttpResponse; overload;
function ReadErrorIDEMessage(const AEMessage: string): Integer;
procedure Excute;
protected
FThread: TCPHttpThread;
FHttp: THTTPClient;
WorkState: TCPWorkState;
OnResponseEvent: TOnResponseEvent;
HttpType: TCPHttpType;
ReqURL, Params, Headers: string;
TryTimes: Integer;
procedure Reset;
procedure Request;
procedure Stop;
procedure UpdateError(const AError: string);
procedure UpdateCompleted(const AResponse: IHTTPResponse);
procedure SynchNotifyResponse(const AHttpResponse: TCPHttpResponse);
public
constructor Create;
destructor Destroy; override;
end;
private
FRequestList: TCustomDataList<TCPHttpItem>;
procedure ClearData;
function GetWorkHttpItem: TCPHttpItem;
protected
procedure HttpRequest(const AHttpType: TCPHttpType; const AReqURL, AParams, AHeaders: string;
const AOnResponseEvent: TOnResponseEvent);
public
constructor Create();
destructor Destroy; override;
procedure Get(const AReqURL, AParams, AHeaders: string; const AOnResponseEvent: TOnResponseEvent);
procedure Post(const AReqURL, AParams, AHeaders: string; const AOnResponseEvent: TOnResponseEvent);
end;
implementation
uses System.Threading, uLogSystem;
const
V_MaxTryTimes = ;
{ TCPHttpClient }
procedure TCPHttpClient.ClearData;
var
I: Integer;
AHttpItem: TCPHttpItem;
begin
FRequestList.Lock;
try
for I := to FRequestList.Count - do
begin
AHttpItem := FRequestList.Items[I];
AHttpItem.FHttp.OnReceiveData := nil;
AHttpItem.Free;
end;
FRequestList.Clear;
finally
FRequestList.UnLock;
end;
end;
constructor TCPHttpClient.Create;
begin
FRequestList := TCustomDataList<TCPHttpItem>.Create;
end;
destructor TCPHttpClient.Destroy;
begin
ClearData;
FRequestList.Free;
inherited;
end;
procedure TCPHttpClient.Get(const AReqURL, AParams, AHeaders: string; const AOnResponseEvent: TOnResponseEvent);
begin
HttpRequest(ht_Get, AReqURL, AParams, AHeaders, AOnResponseEvent);
end;
procedure TCPHttpClient.Post(const AReqURL, AParams, AHeaders: string; const AOnResponseEvent: TOnResponseEvent);
begin
HttpRequest(ht_Post, AReqURL, AParams, AHeaders, AOnResponseEvent);
end;
function TCPHttpClient.GetWorkHttpItem: TCPHttpItem;
var
I: Integer;
AHttpItem: TCPHttpItem;
begin
FRequestList.Lock;
try
for I := to FRequestList.Count - do
begin
AHttpItem := FRequestList.Items[I];
if AHttpItem.WorkState = ws_Wait then
begin
Result := AHttpItem;
Result.WorkState := ws_Work;
Exit;
end;
end;
Result := TCPHttpItem.Create;
Result.WorkState := ws_Work;
FRequestList.Add(Result);
finally
FRequestList.UnLock;
end;
end;
procedure TCPHttpClient.HttpRequest(const AHttpType: TCPHttpType; const AReqURL, AParams, AHeaders: string;
const AOnResponseEvent: TOnResponseEvent);
var
AHttpItem: TCPHttpItem;
begin
AHttpItem := GetWorkHttpItem;
AHttpItem.HttpType := AHttpType;
AHttpItem.ReqURL := AReqURL;
AHttpItem.Params := AParams;
AHttpItem.Headers := AHeaders;
AHttpItem.OnResponseEvent := AOnResponseEvent;
AHttpItem.Request;
end;
{ TCPHttpClient.TCPHttpItem }
constructor TCPHttpClient.TCPHttpItem.Create;
begin
FHttp := THTTPClient.Create;
FHttp.OnReceiveData := DoHttpReceiveData;
FHttp.ConnectionTimeout := ;
FHttp.ResponseTimeout := ;
WorkState := ws_Wait;
FThread := nil;
end;
destructor TCPHttpClient.TCPHttpItem.Destroy;
begin
Reset;
Stop;
FHttp.Free;
inherited;
end;
procedure TCPHttpClient.TCPHttpItem.DoHttpReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64;
var Abort: Boolean);
begin
end;
procedure TCPHttpClient.TCPHttpItem.Excute;
procedure HandleException(const AEMessage: string);
var
AErrorID: Integer;
begin
if FThread.Terminated then
begin
WriteLog(ClassName, 'FThread.Terminated true:' + Integer(Self).ToString);
Exit;
end;
Inc(TryTimes);
AErrorID := ReadErrorIDEMessage(AEMessage);
if ((AErrorID = V_HttpResponse_ConnectFail) or (AErrorID = V_HttpResponse_ReadTimeOut)) and
(TryTimes < V_MaxTryTimes) then
Excute
else
UpdateError(AEMessage);
end;
var
AHttpURL: string;
AParamList: TStringList;
AResponse: IHTTPResponse;
begin
case HttpType of
ht_Get:
begin
if Params.IsEmpty then
AHttpURL := ReqURL
else
AHttpURL := ReqURL + '?' + Params;
try
AResponse := FHttp.Get(AHttpURL);
UpdateCompleted(AResponse);
except
on E: Exception do
begin
HandleException(E.Message);
end;
end;
end;
ht_Post:
begin
AHttpURL := ReqURL;
AParamList := TStringList.Create;
try
AParamList.Text := Trim(Params);
try
AResponse := FHttp.Post(AHttpURL, AParamList);
UpdateCompleted(AResponse);
except
on E: Exception do
begin
HandleException(E.Message);
end;
end;
finally
AParamList.Free;
end;
end;
ht_Put:
;
end;
end;
procedure TCPHttpClient.TCPHttpItem.Request;
begin
if not Assigned(FThread) then
begin
FThread := TCPHttpThread.Create(True);
FThread.FreeOnTerminate := False;
FThread.OnExecuteProc := Excute;
FThread.Start;
end
else
begin
if FThread.Suspended then
{$WARN SYMBOL_DEPRECATED OFF}
FThread.Resume;
{$WARN SYMBOL_DEPRECATED ON}
end;
end;
procedure TCPHttpClient.TCPHttpItem.Reset;
begin
TryTimes := ;
OnResponseEvent := nil;
WorkState := ws_Wait;
end;
procedure TCPHttpClient.TCPHttpItem.Stop;
begin
if Assigned(FThread) then
begin
if FThread.Suspended then
{$WARN SYMBOL_DEPRECATED OFF}
FThread.Resume;
{$WARN SYMBOL_DEPRECATED ON}
FThread.Terminate;
FThread.WaitFor;
FThread.Free;
FThread := nil;
end;
end;
procedure TCPHttpClient.TCPHttpItem.SynchNotifyResponse(const AHttpResponse: TCPHttpResponse);
var
AResponse: TCPHttpResponse;
begin
AResponse := AHttpResponse;
if AResponse.StatusCode = V_HttpResponse_Success then
WriteLog(ClassName, Format('%d %s', [AResponse.StatusCode, AResponse.HttpData]))
else
WriteLog(ClassName, Format('%d %s', [AResponse.StatusCode, AResponse.ErrorMsg]));
if Assigned(OnResponseEvent) then
TThread.Synchronize(FThread,
procedure
begin
if FThread.Terminated then
Exit;
OnResponseEvent(AResponse);
end);
end;
procedure TCPHttpClient.TCPHttpItem.UpdateError(const AError: string);
begin
SynchNotifyResponse(ConvertResponse(AError));
Reset;
end;
procedure TCPHttpClient.TCPHttpItem.UpdateCompleted(const AResponse: IHTTPResponse);
begin
if Assigned(AResponse) then
begin
SynchNotifyResponse(ConvertResponse(AResponse));
Reset;
end
else
raise Exception.Create('UpdateCompleted AResponse is nil');
end;
function TCPHttpClient.TCPHttpItem.ConvertResponse(const AResponse: IHTTPResponse): TCPHttpResponse;
var
AStringStream: TStringStream;
begin
FillChar(Result, sizeof(TCPHttpResponse), #);
Result.StatusCode := AResponse.StatusCode;
AStringStream := TStringStream.Create('', TEncoding.UTF8);
try
AStringStream.LoadFromStream(AResponse.ContentStream);
if Result.StatusCode = V_HttpResponse_Success then
Result.HttpData := AStringStream.DataString
else
Result.ErrorMsg := AStringStream.DataString;
finally
AStringStream.Free;
end;
end;
function TCPHttpClient.TCPHttpItem.ReadErrorIDEMessage(const AEMessage: string): Integer;
var
AStartIndex, AStopIndex: Integer;
begin
AStartIndex := Pos('(', AEMessage) + ;
AStopIndex := Pos(')', AEMessage) - ;
Result := StrToIntDef(Copy(AEMessage, AStartIndex, AStopIndex - AStartIndex + ), MaxInt - );
end;
function TCPHttpClient.TCPHttpItem.ConvertResponse(const AError: string): TCPHttpResponse;
begin
FillChar(Result, sizeof(TCPHttpResponse), #);
Result.StatusCode := ReadErrorIDEMessage(AError);
Result.ErrorMsg := AError;
end;
{ TCPHttpClient.TCPHttpThread }
procedure TCPHttpClient.TCPHttpThread.Execute;
begin
inherited;
while not Terminated do
begin
if Assigned(FOnExecuteProc) then
FOnExecuteProc;
if not Terminated then
{$WARN SYMBOL_DEPRECATED OFF}
Suspend;
{$WARN SYMBOL_DEPRECATED ON}
end;
end;
end.

分享一个Delphi跨平台Http库的封装,一个Delphi跨平台TCP库的封装的更多相关文章

  1. C 封装一个通用链表 和 一个简单字符串开发库

    引言 这里需要分享的是一个 简单字符串库和 链表的基库,代码也许用到特定技巧.有时候回想一下, 如果我读书的时候有人告诉我这些关于C开发的积淀, 那么会走的多直啊.刚参加工作的时候做桌面开发, 服务是 ...

  2. C 封装一个简单二叉树基库

    引文 今天分享一个喜欢佩服的伟人,应该算人类文明极大突破者.收藏过一张纸币类型如下 那我们继续科普一段关于他的简介 '高斯有些孤傲,但令人惊奇的是,他春风得意地度过了中产阶级的一生,而  没有遭受到冷 ...

  3. 使用libzplay库封装一个音频类

    装载请说明原地址,谢谢~~      前两天我已经封装好一个duilib中使用的webkit内核的浏览器控件和一个基于vlc的用于播放视频的视频控件,这两个控件可以分别用在放酷狗播放器的乐库功能和MV ...

  4. 仿照jquery封装一个自己的js库(一)

    所谓造轮子的好处就是复习知识点,加深对原版jquery的理解. 本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现.主要涉及知识点包 ...

  5. [js高手之路] 跟GhostWu一起封装一个字符串工具库-架构篇(1)

    所谓字符串工具库就是利用javascript面向对象的知识封装一个常用的字符串处理方法库,首先给这个库起个名字,好吧就叫ghostwu.js. 看下ghostwu.js的整体架构: ; (functi ...

  6. 仿照jquery封装一个自己的js库

    所谓造轮子的好处就是复习知识点,加深对原版jquery的理解.本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现.主要涉及知识点包括 ...

  7. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  8. 【JavaScript框架封装】自己动手封装一个涵盖JQuery基本功能的框架及核心源码分享(单文件版本)

    整个封装过程及阅读JQuery源码的过程基本上持续了一个月吧,最终实现了一个大概30%的JQuery功能的框架版本,但是里面涉及的知识点也是非常多的,总共的代码加上相关的注释大概在3000行左右吧,但 ...

  9. 如何封装一个Cookie库

    由Cookie详解我们已经了解到了Cookie是为了实现有状态的基于HTTP协议的应用而存在的.一个Cookie的由以下几个部分组成: //设置cookie的格式和Set-Cookie头中使用的格式一 ...

  10. [dotnet] 封装一个同时支持密码/安全密钥认证的SFTP下载器,简单易用。

    前言 最近在开发订单对账系统,先从各种支付平台获取订单销售数据,然后与公司商城订单数据进行对账兜底.总体上,各个支付平台提供数据的方式分为两类,一般以接口的方式提供实时数据,比如:webservice ...

随机推荐

  1. 让webStorm支持自动监听编译scss文件

    前提概要 今日,重装了两波系统,,,之前安装的各种环境都忘光了,重新又踩一次坑的感觉很不舒服,所以记录一下配置自动编译scss一路遇到的坑 一.webstrom run的时候控制台输出的错误中文提示乱 ...

  2. E20180601-hm

    trade-off n. 权衡; 交易;(不是商业方面的交易,而是“利”与“弊”的权衡) vertex n. 顶点; 最高点; <数>(三角形.圆锥体等与底相对的)顶; (三角形.多边形等 ...

  3. jade安装及基本语法使用

    一.cmd安装jade: cnpm install -g jade //cnom install jade -g与上面使用效果一致. 二.jade命令行中使用: 使用cmd: jade index.j ...

  4. [Xcode 实际操作]七、文件与数据-(19)颜色集(Color Set)的使用

    目录:[Swift]Xcode实际操作 本文将演示颜色集合的使用. 使用颜色集合可以很方便地创建应用程序的主题色,并且可以方便的对主题颜色进行更换. 要使用颜色集功能,需要设置项目的部署(Deploy ...

  5. 解决element 照片墙上传时回显问题

    1.先看看样式: <el-upload class="imgList" action="1165165" list-type="picture- ...

  6. PHP实现用户登录注册功能

    初学php做了一些比较常见且有用的页面,放在上面记录一下咯 我是用了bootstrap框架里面的模态框做注册登陆页面,这样页面比较美观 页面效果: 注册成功条件/功能: 1)用户名不能冲突 2)两次密 ...

  7. native-echarts 在安卓上无法显示出来

    1.native-echarts 的配置是百度echarts 2.模拟器上试了很多次都显示不出来(具体不清楚,我的是这样) 3.真机测试可以显示图表,以下是配置: a.将node_modules\na ...

  8. 超简单 Promise封装小程序ajax 超好用 以及封装登录

    //网络类 //封装网络请求 const ajax = (ajaxData, method) => { wx.showLoading({ title: '加载中', mask: true }); ...

  9. python多线程Event实现红绿灯案例

    代码: # __author__ = 'STEVEN' # coding = utf-8 import time,threading #开启事件 event = threading.Event() c ...

  10. Linux —— 压缩命令

    压缩与解压命令 .zip格式 压缩文件: zip 压缩文件名 原文件名 (压缩目录添加 -r) 解压缩文件/目录: unzip .zip压缩包 .gz格式 压缩文件: gzip 原文件名称 压缩文件为 ...