delphi中利用Indy的TIdFtp控件实现FTP协议

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

delphi中利用Indy的TIdFtp控件实现FTP协议版权声明:本文为博主原创文章,未经博主允许不得转载。现在很多应用都需要上传与下载大型文件,通过HTTP方式上传大文件有一定的局限性。幸好FTP作为一个非常老而且非常成熟的协议可以高效稳定地完 成大文件的上传下载,并且可以完美地实现续传。就拿我写的电影服务器管理端程序来说,各种方案比较后,发现使用FTP可以完美地实现要求。但是要通过 WinSocket库实现FTP比较麻烦,幸好有Indy--一个包装了大多数网络协议的组件包。通过Indy,程序设计人员可以通过阻塞方式进行编程,可以抛开蹩脚的Winsocket异步模式,采用与Unix系统上等同的阻塞编程模式进行。这样,程序员就可以很好的处理程序的运行流程。下面,我们进入到Indy的TIdFtp世界。1.控件的说明使用Indy 9中的TIdFtp控件可以实现通过FTP方式进行文件的上传与下载。2.控件的具体使用(1)控件属性设置默 认属性即可,与服务器连接直接相关的属性如主机名与用户等在建立连接时进行设定。需要设定的是RecvBufferSize和 SendBufferSize两属性的值。另外需要根据要传输的文件类型指定TransferType属性,而其他属性按默认值设定即可。RecvBufferSize说明(默认值为8192字节):该属性为整型变量,用于指定连接所用的接受缓冲区大小。SendBufferSize 说明(默认值为32768字节):该属性也为整型变量,用于指定连接所用的发送缓冲区的最大值。该属性在WriteStream方法中时,可用于 TStream指定要发送内容的块数。如果要发送的内容大于本属性值,则发送内容被分为多个块发送。TransferType说明(默认 值为ftBinary):该属性为TIdFTPTransferType型变量。用于指定传输内容是二进制文件(ftBinary )还是ASCII文件(ftASCII)。应用程序需要使用二进制方式传输可执行文件、压缩文件和多媒体文件等;而使用ASCII方式传输文本或超文本等 文本型数据。(2)控件的事件响应OnDisconnected响应:TNotifyEvent类,用于响应断开(disconnect)事件。当Disconnect方法被调用用来关闭Socket的时候,触发该响应。应用程序必须指定该事件响应的过程,以便对该断开事件进行相应。OnStatus 响应:TIdStatusEvent类。该响应在当前连接的状态变化时被触发。该事件可由DoStatus方法触发并提供给事件控制器属性。 axStatus是当前连接的TIdStatus值;aaArgs是一个可选的参数用于格式化函数,它将用于构造表现当前连接状态的文本消息。OnWork 响应:OnWord是TWorkEvent类事件的响应控制器。OnWork用于关联DoWork方法当缓冲区读写操作被调用时通知Indy组件和类。它 一般被用于控制进度条和视窗元素的更新。AWorkMode表示当前操作的模式,其中:wmRead-组件正在读取数据;wmWrite-组件正在发送数 据。AWorkCount指示当前操作的字节计数。OnWorkBegin响应:TWorkBeginEvent类。当缓冲区读 写操作初始化时,该事件关联BeginWork方法用于通知Indy组件和类。它一般被用于控制进度条和视窗元素的更新。AWorkMode表示当前操作 的模式,其中:wmRead-组件正在读取数据;wmWrite-组件正在发送数据。AWorkCountMax用于指示发送到OnWorkBegin事 件的操作的最大字节数,0值代表未知。OnWorkEnd响应:TWorkEndEvent类。当缓冲区读写操作终止时,该事件 关联EndWork方法用于通知Indy组件和类。AWorkMode表示当前操作的模式,其中:wmRead-组件正在读取数据;wmWrite-组件 正在发送数据。AWorkCount表示操作的字节数。在事件响应中,主要通过上述五种事件响应来控制程序。在一般情况下,在 OnDisconnected中设定连接断开的界面通知;在OnStatus中设定当前操作的状态;在OnWork中实现传输中状态条和其他参数的显示; 而在OnWorkBegin和OnWorkEnd中分别设定开始传输和传输结束时的界面。(3)连接远程服务器完 成了设定控件属性和实现了控件的事件响应后,就可以与服务器进行交互和传输了。在连接之前,应首先判断IdFtp是否处于连接状态,如果 Connected为False,则通过界面控件或其他方式指定与服务器连接相关的一些TCP类属性的设置,分别是:Host(主机名):String、 Username(用户名):String、Password(密码):String,也可以指定Port(端口)。之后调用Connect方法连接远程 服务器,如果无异常出现则连接成功建立。过程说明:procedure Connect(AAutoLogin: boolean; const ATimeout: Integer);该过程连接远程FTP服务器属性:AAutoLogin: boolean = True连接后自动登录,该参数默认为True。const ATimeout: Integer = IdTimeoutDefault超时时间,单位:秒。示例代码:if IdFTP1.Connected then tryif TransferrignData then IdFTP1.Abort;IdFTP1.Quit;finallyendelse with IdFTP1 do tryUsername := UserIDEdit.Text;Password := PasswordEdit.Text;Host := FtpServerEdit.Text;Connect;ChangeDir(CurrentDirEdit.Text);finallyend;(4)改变目录连 接建立后,可以改变当前FTP会话所在的目录。对于已知绝对路径的情况下,可以直接调用ChangeDir(const ADirName: string)方法来转换目录,ADirName表示服务器上的文件系统目录,另外还可以调用ChangeDirUp回到上级目录。如 果未知路径,则可以通过List(ADest: TStrings; const ASpecifier: string; const ADetails: boolean)过程获取远程服务器的当前目录结构,此时必须设定TransferType为ftASCII(ASCII模式),其中:ADest保存当 前目录结构,可以在后续程序中调用该列表。另外可以通过RetrieveCurrentDir方法获取当前目录名。过程说明:procedure ChangeDir(const ADirName: string);改变工作目录属性const ADirName: string远程服务器的目录描述说明:该过程实际上是实现了FTP CWD命令。procedure ChangeDirUp;到上一级目录function RetrieveCurrentDir: string;该函数返回当前目录名procedure List(ADest: TStrings; const ASpecifier: string; const ADetails: boolean);列出当前目录所有文件和子目录及其属性参数:ADest: TStrings保存文件及子目录的返回结果const ASpecifier: string = ''文件掩码,用于列出符合条件的文件const ADetails: boolean = true包含文件和子目录属性property DirectoryListing: TIdFTPListItems;返回文件及目录结构的列表示例代码:LS := TStringList.Create;tryIdFTP1.ChangeDir(DirName);IdFTP1.TransferType := ftASCII;CurrentDirEdit.Text := IdFTP1.RetrieveCurrentDir;DirectoryListBox.Items.Clear;IdFTP1.List(LS);DirectoryListBox.Items.Assign(LS);if DirectoryListBox.Items.Count > 0 thenif AnsiPos('total', DirectoryListBox.Items[0]) > 0 then DirectoryListBox.Items.Delete(0);finallyLS.Free;end;(5)下载的实现在 下载之前,必须查看DirectoryListing.Items[sCurrFile].ItemType是否为文件,如返回为 ditDirectory则代表当前文件名为目录,不能下载,必须导向到文件才可。如为文件,则可以进行下载。在下载前,设定传输的类型为二进制文件,并 且指定本地要保存的路径。通过调用Get方法,实现文件的下载。下载过程较慢,可以考虑将其放到线程中实现。过程说明:procedure Get(const ASourceFile: string; ADest: TStream; AResume: Boolean); overload;procedure Get(const ASourceFile: string; const ADestFile: string; const ACanOverwrite: boolean; AResume: Boolean); overload;从远程服务器上获取文件。属性说明:const ASourceFile: string远程服务器上的源文件名const ADestFile: string保存到客户机上的文件名const ACanOverwrite: boolean = false重写同名文件AResume: Boolean = false是否进行断点续传示例代码:SaveDialog1.FileName := Name;if SaveDialog1.Execute then beginSetFunctionButtons(false);IdFTP1.TransferType := ftBinary;BytesToTransfer := IdFTP1.Size(Name);if FileExists(Name) then begincase MessageDlg('File aready exists. Do you want to resume the download operation?',mtConfirmation, mbYesNoCancel, 0) ofmrYes: beginBytesToTransfer := BytesToTransfer - FileSizeByName(Name);IdFTP1.Get(Name, SaveDialog1.FileName, false, true);end;mrNo: beginIdFTP1.Get(Name, SaveDialog1.FileName, true);end;mrCancel: beginexit;end;end;endelse beginIdFTP1.Get(Name, SaveDialog1.FileName, false);end;(6)上传的实现上传的实现与下载类似,通过put方法即可。过程说明:procedure Put(const ASource: TStream; const ADestFile: string; const AAppend: boolean); overload;procedure Put(const ASourceFile: string; const ADestFile: string; const AAppend: boolean); overload;上传文件至服务器属性说明:const ASourceFile: string将要被上传的文件const ADestFile: string = ''服务器上的目标文件名const AAppend: boolean = false是否继续上传代码示例:if IdFTP1.Connected then beginif UploadOpenDialog1.Execute then tryIdFTP1.TransferType := ftBinary;IdFTP1.Put(UploadOpenDialog1.FileName, ExtractFileName(UploadOpenDialog1.FileName));//可以在此添加改变目录的代码;finally//完成清除工作end;end;(7)删除的实现删除文件使用Delete方法,该方法删除指定的文件,删除对象必须为文件。如果要删除目录则使用RemoveDir方法。过程说明:procedure Delete(const AFilename: string);删除文件procedure RemoveDir(const ADirName: string);删除文件夹,根据不同的服务器删除文件夹有不同的要求。有些服务器不允许删除非空文件夹,程序员需要添加清空目录的代码。上述两个过程的参数均为目标名称代码示例:if not IdFTP1.Connected then exit;Name := IdFTP1.DirectoryListing.Items[iCurrSelect].FileName;if IdFTP1.DirectoryListing.Items[iCurrSelect].ItemType = ditDirectory then tryidftp1.RemoveDir(Name);finallyendelsetryidftp1.Delete(Name);finallyend;(8)后退的实现后退在实际上是目录操作的一种,可以简单的改变当前目录为..来实现,也可以通过回到上级目录来实现。(9)取消的实现在IdFtp的传输过程中,可以随时使用abort方法取消当前操作。可以的OnWork事件的实现中来确定何时取消操作。代码示例://取消按钮的OnClick响应procedure TMainForm.AbortButtonClick(Sender: TObject);beginAbortTransfer := true;end;//IdFTP的OnWork事件响应procedure TMainForm.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;const AWorkCount: Integer);begin... if AbortTransfer then IdFTP1.Abort;AbortTransfer := false;end;(10)断点续传的实现断点续传就是在上传或下载过程开始时,判断已经传输过的文件是否上传输完毕,如果传输没有成功完成,则在上次中断处继续进行传输工作。实现该功能需要两个重要的操作,首先是判断文件的大小信息,其次是在传输过程Get和Put中指定上传的行为。判断服务器上文件的大小使用函数Size(FileName)。在下载过程中,比较本地文件和远程文件的信息,然后在Get中指定AResume := True即可。而上传也一样,指定Put的AAppend := True就可以了。   在 前面我们讲过,Indy的网络操作大部分是阻塞模式的,TIdFtp也不例外。这样在上述各个操作运行过程的时候用户界面被暂时冻结,必须要等待调用返回 才能继续用户操作界面响应。所以在实际编程中,需要使用多线程的方式来保证户界面的响应。Windows系统可以使用CreateThread系统调用来 创建线程,但是在使用的时候需要开发人员做很多额外的工作来保证线程的同步等问题。而Indy中也包含了实现多线程的控件 TIdThreadComponent,相对比之下该控件实现多线程时更加方便,也更容易控制。我将在后续的文章里为大家介绍 TIdThreadCOmponent的使用方法。下载的一些代码接下来我们来写最主要的代码,也就是下载部分了,首先来看HTTP协议的:
procedure TForm1.HttpDownLoad(aURL, aFile: string; bResume: Boolean);
vartStream: TFileStream;
begin //Http方式下载if FileExists(aFile) then //如果文件已经存在tStream := TFileStream.Create(aFile, fmOpenWrite) elsetStream := TFileStream.Create(aFile, fmCreate);if bResume then //续传方式beginIdHTTP1.Request.ContentRangeStart := tStream.Size - 1;tStream.Position := tStream.Size - 1; //移动到最后继续下载IdHTTP1.Head(aURL);IdHTTP1.Request.ContentRangeEnd := IdHTTP1.Response.ContentLength;end else //覆盖或新建方式beginIdHTTP1.Request.ContentRangeStart := 0;end;tryIdHTTP1.Get(aURL, tStream); //开始下载finallytStream.Free;end;
end;
这里我们同样使用IdHTTP的Get过程,函数的aURL是网址,aFile是保存的文件名,bResume确定是否续传,需要注意的就是续传方式时的代码:IdHTTP1.Request.ContentRangeStart := tStream.Size - 1;tStream.Position := tStream.Size - 1; //移动到最后继续下载IdHTTP1.Head(aURL);IdHTTP1.Request.ContentRangeEnd := IdHTTP1.Response.ContentLength;
第 一行我们将下载开始位置设置为读入文件流的末尾,也就是设置为已经下载了的那部分文件的大小,第二行我们将文件流本身也指向自己的末尾,第三行我们通过 Head过程得到网址头信息,在第四行将头信息的文件总大小赋值给下载的结束的位置,至于这里为什么第一行和第二行代码最后都要-1,我当时没有加-1的 时候在续下载一个完整的已经下载的文件的时候总是提示错误,最后跟踪IdHTTP的代码发现他在处理下载范围的时候如果开始的位置和结束位置一样时会引发 将浮点数转为整数的错误,因而这里加上-1防止这种错误发生,另外一种处理方法就是比较如果开始位置等于结束位置就退出也是可以的。
再来看FTP协议的下载过程:
procedure TForm1.FtpDownLoad(aURL, aFile: string; bResume: Boolean);
vartStream: TFileStream;sName, sPass, sHost, sPort, sDir: string;
begin //ftp方式下载if FileExists(aFile) then //建立文件流tStream := TFileStream.Create(aFile, fmOpenWrite) elsetStream := TFileStream.Create(aFile, fmCreate);GetFTPParams(aURL, sName, sPass, sHost, sPort, sDir);with IdFTP1 dotryif Connected then Disconnect; //重新连接Username := sName;Password := sPass;Host := sHost;Port := StrToInt(sPort);Connect;exceptexit;end;IdFTP1.ChangeDir(sDir); //改变目录BytesToTransfer := IdFTP1.Size(aFile);tryif bResume then //续传begintStream.Position := tStream.Size;IdFTP1.Get(aFile, tStream, True);end elsebeginIdFTP1.Get(aFile, tStream, False);end;finallytStream.Free;end;
end;
这 个过程中我们就用到了GetFTPParams()函数将网址的用户名、密码、主机地址、端口、路径等信息分离出来,IdFTP利用这些信息登陆服务器并 到相应目录,最后利用Get()过程就很容易实现下载了,它的续传就比HTTP协议要简单很多,因为IdFTP的Get()本身就支持续传。
这里我简单穿插一点的内容,一个服务器是否支持断点续传,我们可以通过发送"REST 1"FTP指令来检测,如果返回350则表示支持。
最后我们根据网址来确定使用什么协议来下载:
function TForm1.GetProt(aURL: string): Byte;
begin //检测下载的地址是http还是ftpResult := 0;if Pos('http', LowerCase(aURL)) = 1 thenResult := 1; //http协议if Pos('ftp', LowerCase(aURL)) = 1 thenResult := 2; //ftp协议
end;
这个函数根据网址返回整数供我们使用。
procedure TForm1.MyDownLoad(aURL, aFile: string; bResume: Boolean);
begincase GetProt(aURL) of0: ShowMessage('不可识别的地址!');1: HttpDownLoad(aURL, aFile, bResume);2: FtpDownLoad(aURL, aFile, bResume);end;
end;
这个过程就利用GetProt()函数返回的整数执行相应的协议下载过程。
(2) 接下来看看每个按钮的代码,有了上面的函数,按钮的代码就简单多了:
下载按钮:
procedure TForm1.Button1Click(Sender: TObject);
varaURL, aFile: string;
beginaURL := ComboBox1.Text; //下载地址,例如"http://www.2ccc.com/update/demo.exe";aFile := GetURLFileName(aURL); //得到文件名,例如"demo.exe"if FileExists(aFile) thenbegincase MessageDlg('文件已经存在,是否续传?', mtConfirmation, mbYesNoCancel, 0) ofmrYes: MyDownLoad(aURL, aFile, True); //续传mrNo: MyDownLoad(aURL, aFile, False); //覆盖mrCancel: Exit; //取消end;end else MyDownLoad(aURL, aFile, False); //建立新文件下载
end;
MessageDlg()函数弹出一个对话框让用户选择续传、覆盖还是取消下载。
中断按钮:
procedure TForm1.Button2Click(Sender: TObject);
beginAbortTransfer := True;
end;
前 面忘了介绍,所以这里大家看不明白,AbortTransfer是我们定义的一个私有变量,在开始下载的时候将它设为False,下载的过程中随时监测这 个变量,一旦变为True就利用IdHTTP的Disconnect和IdFTP1的Abort方法中断下载,如果没有下载完就中断,那程序的目录中就会 有一个下载不完整的程序或者其他东西,下次再下载的时候我们就可以选择续传来完成剩下的下载过程。
procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;const AWorkCountMax: Integer);
beginAbortTransfer := False;
……
end;
在IdHTTP1和IdFTP的OnWorkBegin事件我们就将AbortTransfer设置为False了,在他们的Work事件中,我们检测AbortTransfer变量来完成是否中断的操作。
procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;const AWorkCount: Integer);
beginif AbortTransfer thenbegin //中断下载IdHTTP1.Disconnect;IdFTP1.Abort;end;ProgressBar1.Position := AWorkCount;Application.ProcessMessages;
end;
(3) 最后是连接状态等信息的代码:
在IdHTTP和IdFTP的OnStatus事件写入:
procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;const AStatusText: string);
beginListBox1.ItemIndex := ListBox1.Items.Add(AStatusText);
end;
因为IdHTTP和IdFTP在OnWork、OnStatus等事件上执行的代码都是一样的,所以我们只用写其中一个的代码,然后另外一个选择相同的事件就OK了。图8.3.4
3.全部代码写完收工,F9运行一下看看效果,是不是能断点续传。
【程序小结】
本程序主要的功能由IdHTTP和IdFTP组件完成,主要掌握他们的Get过程实现断点续传的方法以及字符串的分析分解方法,这里我们同样使用了流格式,不过这次不是内存流而是文件流。通过本例,读者应该初步掌握调试程序时断点的使用,事件代码的共用等。
【作者后话】
在写完这篇文章不久,作者偶然间察看了Indy系列组件的帮助,发现一个封装了分析URL结构的类TIdURI,在IdURI单元,这个类可以很轻松的将我们上面的GetFTPParams()函数的功能实现,例如:
varURI: TIdURI;
beginURI := TIdURI.Create(aURL); //建立trysProtocol := URI.Protocol; //协议sHost := URI.Host; //主机//……等等都可以通过URI的属性得到finallyURI.Free;end;
end;
使用此类我们的程序可以变得更简单,如何修改就留给读者自己去完善吧。

转载于:https://my.oschina.net/u/582827/blog/872827

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291004.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++之map插入数据相同的key不能覆盖value解决办法

1、问题 C里面,如果map里面插入之前的<key, value>,如果key在map里面有的话&#xff0c;不会覆盖之前的value,一般先判断之前有没有数据&#xff0c;有的话先删除&#xff0c;然后再去添加。 2、代码实现 3、运行结果

【BZOJ】【4145】【AMPPZ2014】The Prices

状压DP/01背包 Orz Gromah 容易发现m的范围很小……只有16&#xff0c;那么就可以状压&#xff0c;用一个二进制数来表示买了的物品的集合。 一种简单直接的想法是&#xff1a;令$f[i][j]$表示前$i$个商店买了状态集合为$j$的商品的最小代价&#xff0c;那么我们转移的时候就需…

WPF 实现人脸检测

WPF开发者QQ群此群已满340500857 &#xff0c;请加新群458041663由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。接着上一篇利用已经训练好的数据文件,检测人脸 地址如下&#xff1a;http…

C++之函数的默认值参数说明

1、思考 今天看到C代码的时候&#xff0c;发现文件里面的函数定义和实现都有3个参数&#xff0c;特码调用的时候只有2个参数了&#xff0c;日了狗&#xff0c;java里面好像没有这种方式&#xff0c;后来才发现是默认参数 2、代码实现 3、展示结果 4、总结 注意默认参数需要写…

插头DP

AC HDU1693 不能再简单了的插头DP 1 #include <cstdio>2 #include <fstream>3 #include <iostream>4 5 #include <cstdlib>6 #include <cstring>7 #include <algorithm>8 #include <cmath>9 10 #include <queue>11 #include…

自定义控件详解(四):Paint 画笔路径效果

Paint 画笔 &#xff0c;即用来绘制图形的"笔" 前面我们知道了Paint的一些基本用法&#xff1a; paint.setAntiAlias(true);//抗锯齿功能 paint.setColor(Color.RED); //设置画笔颜色 paint.setStyle(Style.FILL);//设置填充样式 paint.setStrokeWidth(10);//设…

2021 .NET Conf China 主题分享之-轻松玩转.NET大规模版本升级

去年.NET Conf China 技术大会上&#xff0c;我给大家分享了主题《轻松玩转.NET大规模版本升级》&#xff0c;今天把具体分享的内容整理成一篇博客&#xff0c;供大家研究参考学习。一、先说一下技术挑战和业务背景我们公司&#xff1a;特来电新能源股份有限公司&#xff1a;中…

ASP.NET Core基于滑动窗口算法实现限流控制

前言在实际项目中&#xff0c;为了保障服务器的稳定运行&#xff0c;需要对接口的可访问频次进行限流控制&#xff0c;避免因客户端频繁请求导致服务器压力过大。而AspNetCoreRateLimit[1]是目前ASP.NET Core下最常用的限流解决方案。查看它的实现代码&#xff0c;我发现它使用…

linux操作系统cp命令

转载于:https://www.cnblogs.com/skl374199080/p/3863918.html

sql必读的九本书

2019独角兽企业重金招聘Python工程师标准>>> 原文地址 直接上书(书籍以后会陆续加上去)书籍下载地址 《MySQL必知必会》《SQL学习指南&#xff08;第2版 修订版&#xff09;》《MySQL技术内幕——InnoDB存储引擎》《Redis设计与实现》《ZooKeeper&#xff1a;分布式…

C语言之加入头文件<stdbool.h>可以使用true和false

1、头文件<stdbool.h>介绍 &#xff08;1&#xff09;使用了<stdbool.h>后&#xff0c;可使用true和false来表示真假。 &#xff08;2&#xff09;在循环语句中进行变量声明是C99中才有的&#xff0c;因此编译时显式指明 gcc -stdc99 prime.c 2、最简单的例子 3、…

Nginx负载均衡+转发策略

负载均衡负载均衡(详解)https://cloud.tencent.com/developer/article/1526664--示例1upstream www_server_pool { server 10.0.0.5; server 10.0.0.6&#xff1a;80 weight1 max_fails1 fails_timeout10s; server 10.0.0.7&#xff1a;80 weight1 max_fails2 fails_timeo…

教育行业的互联网焦虑症

2019独角兽企业重金招聘Python工程师标准>>> 文/阑夕 2007年&#xff0c;前新东方名师刘一男在新东方在线&#xff08;网校&#xff09;上的全年课程收入是三千元&#xff0c;四年之后的2011年&#xff0c;这个数字飙升到了四十万&#xff0c;已经和刘一男当年实体…

零基础学人工智能:TensorFlow 入门例子

识别手写图片 因为这个例子是 TensorFlow 官方的例子&#xff0c;不会说的太详细&#xff0c;会加入了一点个人的理解&#xff0c;因为TensorFlow提供了各种工具和库&#xff0c;帮助开发人员构建和训练基于神经网络的模型。TensorFlow 中最重要的概念是张量&#xff08;Tenso…

CA周记 - 用 Visual Studio Code 做基于 .NET MAUI 跨平台移动应用开发

自2010年以来&#xff0c;移动应用开发是非常热门的一个方向&#xff0c;从技术上我们经历了原生应用开发、基于 H5 的 Web App、混合模式的移动应用开发&#xff0c;再到跨平台移动应用开发。.NET 不仅是一个跨平台的应用&#xff0c;也是一个跨应用场景的平台。.NET的移动应用…

P2P网络穿越 NAT穿越

http://blog.csdn.net/mazidao2008/article/details/4933730 —————————————————————————————————————————————————————————————— 穿越NAT的意义&#xff1a; NAT是为了节省IP地址而设计的&#xff0c;但它隐藏了…

C#导入导出.CSV文件

欢迎您成为我的读者&#xff0c;希望这篇文章能给你一些帮助。前言大家好&#xff0c;我是阿辉。今天和大家一起来看看&#xff0c;C#在处理流文件时,我们最常用的导出Excel文件是如何操作的。在日常的业务编码过程中&#xff0c;很多时候需求就要求导出Office能打开的表格文件…

奋斗逼,真牛逼!

▲点击上方第二个findyi关注&#xff0c;回复“1”领取职场资料职场&认知洞察 丨 作者 / 易洋 这是findyi公众号的第304篇原创文章今天下午一个读者咨询我一个问题&#xff1a;这名读者感觉卷不过身边的加班狂人&#xff0c;但又感觉这些人丝毫不给公司创造价值&#xff0…

Entity Framework 批量插入

为什么80%的码农都做不了架构师&#xff1f;>>> 奋斗的小鸟——dogxuefeng Entity Framework 批量插入很慢 Entity Framework 批量插入很慢吗&#xff1f;我自己测试下 前几天看到一篇文章里提到过&#xff0c;在批量插入时&#xff0c;需要加上Context.Configur…

DEV-aspxgridview中的aspcheckbox

checkbox可以所以点击修改 例子演示&#xff1a;http://codecentral.devexpress.com/E2313/ 源程序&#xff1a;https://www.devexpress.com/Support/Center/Example/Details/E2313 表头可以全选所有的checkbook 具体演示如下&#xff1a;http://codecentral.devexpress.com/…