425 Can't open data connection.列出目录失败

本文记录了使用FileZilla连接FTP时遇到的返回425错误的问题及解决过程。作者尝试调整防火墙设置和客户端配置,最终通过设置主动传输模式解决了连接超时和读取目录列表失败的问题。

今天用Filezilla连接ftp,总是出现
返回: 425 Can't open data connection.
错误: 读取目录列表失败
状态: 已从服务器断开

参考官网的提示,说是防火墙没允许通过,配置,无效

发现说是a client configuration problem,按照其说的配置,无效

然后发现提示错误如下:返回:    200 Type set to I.
命令:    PASV
返回:    227 Entering Passive Mode (211,154,132,148,9,114)
命令:    LIST
错误:    连接超时
错误:    读取目录列表失败


建立站点,填入地址,用户名,密码,在传输设置里的传输模式中设置为主动。OK

转载于:https://www.cnblogs.com/wangyueren/archive/2012/09/24/2699664.html

#include <iostream> #include <winsock2.h> #include <string> #include <sstream> #include <fstream> #include <direct.h> // for _getcwd #pragma comment(lib, "ws2_32.lib") #define PORT 2121 #define DATA_PORT_MIN 60000 #define DATA_PORT_MAX 65535 #define BUFFER_SIZE 1024 using namespace std; // 用户认证信息 struct User { string username; string password; bool authenticated = false; }; // 全局变量 User user; SOCKET data_sock = INVALID_SOCKET; // 发送响应消息 void send_response(SOCKET sock, const string& response) { send(sock, response.c_str(), response.size(), 0); } // 解析命令 pair<string, string> parse_command(const string& cmd) { size_t pos = cmd.find(' '); if (pos == string::npos) return {cmd, ""}; return {cmd.substr(0, pos), cmd.substr(pos + 1)}; } // 列出目录 void list_directory(SOCKET sock) { char cwd[FILENAME_MAX]; _getcwd(cwd, sizeof(cwd)); string response = "226 Directory send OK.\r\n"; send_response(sock, response); // 发送文件列表 string dir_list = ""; for (const auto& entry : experimental::filesystem::directory_iterator(cwd)) { dir_list += entry.path().filename().string() + "\r\n"; } send(data_sock, dir_list.c_str(), dir_list.size(), 0); } // 下载文件 void download_file(SOCKET sock, const string& filename) { ifstream file(filename, ios::binary); if (!file) { send_response(sock, "550 File not found.\r\n"); return; } send_response(sock, "150 Opening data connection.\r\n"); // 发送文件内容 file.seekg(0, ios::end); int length = file.tellg(); file.seekg(0, ios::beg); char buffer[BUFFER_SIZE]; while (length > 0) { int bytes = min(BUFFER_SIZE, length); file.read(buffer, bytes); send(data_sock, buffer, file.gcount(), 0); length -= file.gcount(); } file.close(); send_response(sock, "226 Transfer complete.\r\n"); } // 上传文件 void upload_file(SOCKET sock, const string& filename) { ofstream file(filename, ios::binary); if (!file) { send_response(sock, "553 Could not create file.\r\n"); return; } send_response(sock, "150 Opening data connection.\r\n"); // 接收文件内容 char buffer[BUFFER_SIZE]; int bytes; while ((bytes = recv(data_sock, buffer, BUFFER_SIZE, 0)) > 0) { file.write(buffer, bytes); } file.close(); send_response(sock, "226 Transfer complete.\r\n"); } // 创建数据连接(被动模式) bool create_data_connection(SOCKET control_sock, string& pasv_response) { closesocket(data_sock); sockaddr_in data_addr; data_addr.sin_family = AF_INET; data_addr.sin_addr.s_addr = INADDR_ANY; data_addr.sin_port = htons(DATA_PORT_MIN + rand() % (DATA_PORT_MAX - DATA_PORT_MIN + 1)); data_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (data_sock == INVALID_SOCKET) return false; if (bind(data_sock, (sockaddr*)&data_addr, sizeof(data_addr)) == SOCKET_ERROR) return false; listen(data_sock, 1); string ip = inet_ntoa(((sockaddr_in*)(&data_addr))->sin_addr); stringstream ss; ss << "227 Entering Passive Mode (" << replace(ip.begin(), ip.end(), '.', ',') << ',' << ((ntohs(data_addr.sin_port) >> 8) & 0xFF << ',' << (ntohs(data_addr.sin_port) & 0xFF) << ").\r\n"; pasv_response = ss.str(); return true; } int main() { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { cerr << "Winsock initialization failed." << endl; return 1; } SOCKET server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server_sock == INVALID_SOCKET) { cerr << "Socket creation failed." << endl; WSACleanup(); return 1; } sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_sock, (sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) { cerr << "Bind failed." << endl; closesocket(server_sock); WSACleanup(); return 1; } if (listen(server_sock, 1) == SOCKET_ERROR) { cerr << "Listen failed." << endl; closesocket(server_sock); WSACleanup(); return 1; } cout << "FTP Server started on port " << PORT << endl; while (true) { SOCKET client_sock = accept(server_sock, NULL, NULL); if (client_sock == INVALID_SOCKET) continue; send_response(client_sock, "220 Welcome to the FTP server.\r\n"); string command; char buffer[BUFFER_SIZE]; while (true) { int bytes = recv(client_sock, buffer, BUFFER_SIZE - 1, 0); if (bytes <= 0) break; buffer[bytes] = '\0'; command = buffer; pair<string, string> cmd_pair = parse_command(command); string cmd = cmd_pair.first; string arg = cmd_pair.second; if (cmd == "USER") { user.username = arg; send_response(client_sock, "331 Please specify the password.\r\n"); } else if (cmd == "PASS") { if (user.username == "ftp" && arg == "password") { user.authenticated = true; send_response(client_sock, "230 Login successful.\r\n"); } else { send_response(client_sock, "530 Login incorrect.\r\n"); } } else if (cmd == "PASV") { string pasv_response; if (create_data_connection(client_sock, pasv_response)) { send_response(client_sock, pasv_response); } else { send_response(client_sock, "425 Can't open data connection.\r\n"); } } else if (cmd == "LIST") { if (!user.authenticated) { send_response(client_sock, "530 Not logged in.\r\n"); continue; } sockaddr_in client_addr; int addr_len = sizeof(client_addr); SOCKET data_client = accept(data_sock, (sockaddr*)&client_addr, &addr_len); if (data_client == INVALID_SOCKET) { send_response(client_sock, "425 Can't open data connection.\r\n"); continue; } list_directory(data_client); closesocket(data_client); } else if (cmd == "RETR") { if (!user.authenticated) { send_response(client_sock, "530 Not logged in.\r\n"); continue; } sockaddr_in client_addr; int addr_len = sizeof(client_addr); SOCKET data_client = accept(data_sock, (sockaddr*)&client_addr, &addr_len); if (data_client == INVALID_SOCKET) { send_response(client_sock, "425 Can't open data connection.\r\n"); continue; } download_file(client_sock, arg); closesocket(data_client); } else if (cmd == "STOR") { if (!user.authenticated) { send_response(client_sock, "530 Not logged in.\r\n"); continue; } sockaddr_in client_addr; int addr_len = sizeof(client_addr); SOCKET data_client = accept(data_sock, (sockaddr*)&client_addr, &addr_len); if (data_client == INVALID_SOCKET) { send_response(client_sock, "425 Can't open data connection.\r\n"); continue; } data_sock = data_client; upload_file(client_sock, arg); closesocket(data_client); } else if (cmd == "QUIT") { send_response(client_sock, "221 Goodbye.\r\n"); break; } else { send_response(client_sock, "502 Command not implemented.\r\n"); } } closesocket(client_sock); } closesocket(server_sock); WSACleanup(); return 0; } 根据以上代码在VS2010中使用C++创建相对应的FTP服务器
06-20
unit main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, DB, PostgreSQLUniProvider, Uni, MemDS, DBAccess, GridsEh, DBGridEh, DBGridEhGrouping, ToolCtrlsEh, DBGridEhToolCtrls, DynVarsEh, EhLibVCL, Vcl.Buttons, Vcl.ComCtrls, Vcl.Menus, Vcl.DBCtrls, Vcl.Mask, IdTCPClient, DBAxisGridsEh, DBGridEhImpExp, DBCtrlsEh, DataSetImpExpEh, System.UITypes, ShellAPI,Vcl.Clipbrd, SynEditHighlighter, SynHighlighterSQL, SynAutoCorrect, SynCompletionProposal, SynEdit, SynMemo,SynEditTypes; type TForm1 = class(TForm) Panel1: TPanel; Label1: TLabel; cbConnections: TComboBox; Label2: TLabel; btnExecute: TButton; Panel2: TPanel; DBGridEh0: TDBGridEh; UniConnection0: TUniConnection; UniQuery1: TUniQuery; btnUpdate: TButton; btnExportExcel: TButton; SaveDialog1: TSaveDialog; StatusBar1: TStatusBar; btnExit1: TButton; UniDataSource0: TUniDataSource; lstTables: TListBox; // 新增列表控件 // DBGridEh1: TDBGridEh; // 新增DBGridEh控件 UniQueryTables: TUniQuery; // 用于获取表信息的查询 UniQueryFields: TUniQuery; // 用于获取字段信息的查询 UniDataSource1: TUniDataSource; DBGridEh1: TDBGridEh; pmTables: TPopupMenu; SynCompletionProposal1: TSynCompletionProposal; SynAutoComplete1: TSynAutoComplete; SynAutoCorrect1: TSynAutoCorrect; SynEdit1: TSynEdit; SynSQLSyn1: TSynSQLSyn; // 新增数据源 procedure FormCreate(Sender: TObject); procedure btnExecuteClick(Sender: TObject); procedure btnUpdateClick(Sender: TObject); procedure btnExportExcelClick(Sender: TObject); procedure cbConnectionsChange(Sender: TObject); procedure btnExit1Click(Sender: TObject); procedure lstTablesClick(Sender: TObject); procedure SynCompletionProposal1Execute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean); procedure SynEdit1DblClick(Sender: TObject); procedure SynEdit1KeyPress(Sender: TObject; var Key: Char); private { Private declarations } procedure LoadConnections; procedure ConnectToDatabase(Index: Integer); procedure LoadTables; // 加载所有表 procedure LoadFields(const TableFullName: string); // 加载选定表的所有字段 function TestNetworkConnection(const Server: string; Port: Integer): Boolean; procedure lstTablesContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); procedure DBGridEh1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); procedure CopyTableNameToClipboard(Sender: TObject); procedure CopyFieldNameToClipboard(Sender: TObject); procedure InitHighlighter; procedure LoadDatabaseSchema; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses ExcelXP, ComObj; function TForm1.TestNetworkConnection(const Server: string; Port: Integer): Boolean; var Client: TIdTCPClient; begin Result := False; Client := TIdTCPClient.Create(nil); try Client.Host := Server; Client.Port := Port; try Client.Connect; Result := Client.Connected; Client.Disconnect; except Result := False; end; finally Client.Free; end; end; procedure TForm1.lstTablesContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); var ItemIndex: Integer; TableName: string; MenuItem: TMenuItem; begin // 获取当前鼠标位置对应的项索引 ItemIndex := lstTables.ItemAtPos(MousePos, True); if ItemIndex >= 0 then begin lstTables.ItemIndex := ItemIndex; TableName := lstTables.Items[ItemIndex]; // 清空现有菜单项 pmTables.Items.Clear; // 创建新的菜单项 MenuItem := TMenuItem.Create(pmTables); MenuItem.Caption := '复制表名: ' + TableName; MenuItem.OnClick := CopyTableNameToClipboard; pmTables.Items.Add(MenuItem); // 显示弹出菜单 pmTables.Popup(MousePos.X + lstTables.Left, MousePos.Y + lstTables.Top); Handled := True; // 阻止默认的弹出菜单 end; end; procedure TForm1.SynCompletionProposal1Execute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean); var FieldsQuery: TUniQuery; SchemaName, TableName, CurrentWord, FullTableName: string; DotPos, LastDotPos: Integer; CaretPos: TBufferCoord; LineText: string; StartPos: Integer; begin CanExecute := UniConnection0.Connected; if not CanExecute then Exit; try // 获取当前光标位置 CaretPos := SynEdit1.CaretXY; // 获取当前行的文本 if CaretPos.Line > 0 then LineText := SynEdit1.Lines[CaretPos.Line - 1] else LineText := ''; // 从光标位置向前查找,获取完整的单词(包括点号) StartPos := CaretPos.Char; while (StartPos > 1) and (StartPos <= Length(LineText)) and (LineText[StartPos - 1] in ['a'..'z', 'A'..'Z', '0'..'9', '_', '.']) do Dec(StartPos); if StartPos <= Length(LineText) then CurrentWord := Copy(LineText, StartPos, CaretPos.Char - StartPos) else CurrentWord := ''; // 查找最后一个点号的位置 LastDotPos := LastDelimiter('.', CurrentWord); if LastDotPos = 0 then begin // 没有点号,显示所有表名 SynCompletionProposal1.ItemList.BeginUpdate; try SynCompletionProposal1.ItemList.Clear; LoadDatabaseSchema; finally SynCompletionProposal1.ItemList.EndUpdate; end; end else begin // 有点号,检查点号是否在末尾(表示需要字段提示) if LastDotPos = Length(CurrentWord) then begin // 点号在末尾,获取模式名和表名 FullTableName := Copy(CurrentWord, 1, LastDotPos - 1); // 解析模式名和表名 DotPos := LastDelimiter('.', FullTableName); if DotPos > 0 then begin SchemaName := Copy(FullTableName, 1, DotPos - 1); TableName := Copy(FullTableName, DotPos + 1, Length(FullTableName) - DotPos); end else begin SchemaName := 'public'; // 默认模式 TableName := FullTableName; end; // 验证表名和模式名不为空 if (Trim(TableName) = '') or (Trim(SchemaName) = '') then begin SynCompletionProposal1.ItemList.Clear; Exit; end; FieldsQuery := TUniQuery.Create(nil); try FieldsQuery.Connection := UniConnection0; FieldsQuery.SQL.Text := 'SELECT column_name ' + 'FROM information_schema.columns ' + 'WHERE table_name = :table_name ' + 'AND table_schema = :schema_name ' + 'ORDER BY ordinal_position'; FieldsQuery.ParamByName('table_name').AsString := TableName; FieldsQuery.ParamByName('schema_name').AsString := SchemaName; FieldsQuery.Open; SynCompletionProposal1.ItemList.BeginUpdate; try SynCompletionProposal1.ItemList.Clear; if FieldsQuery.RecordCount = 0 then begin // 尝试不区分大小写查询 FieldsQuery.Close; FieldsQuery.SQL.Text := 'SELECT column_name ' + 'FROM information_schema.columns ' + 'WHERE LOWER(table_name) = LOWER(:table_name) ' + 'AND LOWER(table_schema) = LOWER(:schema_name) ' + 'ORDER BY ordinal_position'; FieldsQuery.ParamByName('table_name').AsString := TableName; FieldsQuery.ParamByName('schema_name').AsString := SchemaName; FieldsQuery.Open; end; if FieldsQuery.RecordCount = 0 then begin SynCompletionProposal1.ItemList.Add('未找到字段 - 检查表名: ' + SchemaName + '.' + TableName); Exit; end; while not FieldsQuery.Eof do begin SynCompletionProposal1.ItemList.Add( FieldsQuery.FieldByName('column_name').AsString ); FieldsQuery.Next; end; finally SynCompletionProposal1.ItemList.EndUpdate; end; finally FieldsQuery.Free; end; end else begin // 点号不在末尾,显示表名提示 SynCompletionProposal1.ItemList.BeginUpdate; try SynCompletionProposal1.ItemList.Clear; LoadDatabaseSchema; finally SynCompletionProposal1.ItemList.EndUpdate; end; end; end; except on E: Exception do begin SynCompletionProposal1.ItemList.Clear; SynCompletionProposal1.ItemList.Add('错误: ' + E.Message); // 记录详细错误信息 OutputDebugString(PChar('自动完成错误: ' + E.Message + ' Class: ' + E.ClassName)); end; end; if SynCompletionProposal1.ItemList.Count = 0 then begin SynCompletionProposal1.ItemList.Add('(无匹配项)'); end; end; procedure TForm1.SynEdit1DblClick(Sender: TObject); begin SynEdit1.SelectAll; end; procedure TForm1.SynEdit1KeyPress(Sender: TObject; var Key: Char); begin // 当输入点号时触发自动完成 if Key = '.' then begin if not UniConnection0.Connected then begin ShowMessage('数据库未连接'); Key := #0; Exit; end; // 先插入点号 SynEdit1.SelText := '.'; // 立即触发自动完成 SynCompletionProposal1.ActivateCompletion; Key := #0; // 阻止默认处理 end // Ctrl+Space 触发自动完成 else if (Key = ' ') and (GetKeyState(VK_CONTROL) < 0) then begin Key := #0; SynCompletionProposal1.ActivateCompletion; end; end; procedure TForm1.InitHighlighter; begin SynSQLSyn1.SQLDialect := sqlPostgres; SynSQLSyn1.KeyAttri.Foreground := clNavy; SynSQLSyn1.CommentAttri.Foreground := clGreen; SynSQLSyn1.StringAttri.Foreground := clMaroon; SynEdit1.Highlighter := SynSQLSyn1; SynEdit1.Options := SynEdit1.Options + [eoAutoIndent, eoScrollPastEol]; end; procedure TForm1.DBGridEh1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); var AHitTest: TGridCoord; // 使用 TGridCoord 替代 TGridHitTestInfoEh FieldName: string; MenuItem: TMenuItem; Cell: TGridCoord; begin // 获取鼠标点击位置的单元格坐标 Cell := DBGridEh1.MouseCoord(MousePos.X, MousePos.Y); if (Cell.X >= 0) and (Cell.Y >= 0) and (UniQueryFields.Active) and (not UniQueryFields.IsEmpty) and (Cell.X = 0) then // column_name 列 begin // 定位到对应行 UniQueryFields.RecNo := Cell.Y + 1; FieldName := UniQueryFields.FieldByName('column_name').AsString; // 清空现有菜单项 pmTables.Items.Clear; // 创建新的菜单项 MenuItem := TMenuItem.Create(pmTables); MenuItem.Caption := '复制字段名: ' + FieldName; MenuItem.OnClick := CopyFieldNameToClipboard; pmTables.Items.Add(MenuItem); // 显示弹出菜单 pmTables.Popup(MousePos.X + DBGridEh1.Left, MousePos.Y + DBGridEh1.Top); Handled := True; // 阻止默认的弹出菜单 end; end; procedure TForm1.LoadDatabaseSchema; var TablesQuery: TUniQuery; begin if not UniConnection0.Connected then begin OutputDebugString('数据库未连接'); Exit; end; try TablesQuery := TUniQuery.Create(nil); try TablesQuery.Connection := UniConnection0; TablesQuery.SQL.Text := 'SELECT table_schema, table_name ' + 'FROM information_schema.tables ' + 'WHERE table_catalog = current_database() ' + 'AND table_schema NOT IN (''information_schema'', ''pg_catalog'') ' + 'AND table_type = ''BASE TABLE'' ' + 'ORDER BY table_schema, table_name'; TablesQuery.Open; SynCompletionProposal1.ItemList.BeginUpdate; try SynCompletionProposal1.ItemList.Clear; while not TablesQuery.Eof do begin SynCompletionProposal1.ItemList.Add( TablesQuery.FieldByName('table_schema').AsString + '.' + TablesQuery.FieldByName('table_name').AsString ); TablesQuery.Next; end; if SynCompletionProposal1.ItemList.Count = 0 then SynCompletionProposal1.ItemList.Add('(没有找到表)'); finally SynCompletionProposal1.ItemList.EndUpdate; end; finally TablesQuery.Free; end; except on E: Exception do begin SynCompletionProposal1.ItemList.Clear; SynCompletionProposal1.ItemList.Add('加载架构失败: ' + E.Message); // 记录详细错误 OutputDebugString(PChar('架构加载错误: ' + E.ClassName + ' - ' + E.Message)); end; end; // 确保列表不为空 if SynCompletionProposal1.ItemList.Count = 0 then begin SynCompletionProposal1.ItemList.Add('(无可用建议)'); // CanExecute := False; // 阻止空列表弹出 end; end; procedure TForm1.CopyTableNameToClipboard(Sender: TObject); var TableName: string; begin if lstTables.ItemIndex >= 0 then begin TableName := lstTables.Items[lstTables.ItemIndex]; Clipboard.AsText := TableName; StatusBar1.Panels[0].Text := '已复制表名: ' + TableName; end; end; procedure TForm1.CopyFieldNameToClipboard(Sender: TObject); var FieldName: string; begin if UniQueryFields.Active and not UniQueryFields.IsEmpty then begin FieldName := UniQueryFields.FieldByName('column_name').AsString; Clipboard.AsText := FieldName; StatusBar1.Panels[0].Text := '已复制字段名: ' + FieldName; end; end; procedure TForm1.FormCreate(Sender: TObject); begin LoadConnections; if cbConnections.Items.Count > 0 then begin cbConnections.ItemIndex := 0; // 尝试连接 ConnectToDatabase(0); end; // 修改自动完成设置 SynCompletionProposal1.Options := [scoLimitToMatchedText, scoUseInsertList, scoEndCharCompletion]; SynCompletionProposal1.EndOfTokenChr := ' .()=,;'; SynCompletionProposal1.TriggerChars := '.'; // 点号触发 SynCompletionProposal1.ShortCut := 16416; // Ctrl+Space LoadTables; // 加载所有表 // 创建弹出菜单实例(如果设计时没有创建) if not Assigned(pmTables) then pmTables := TPopupMenu.Create(Self); // 关联右键菜单事件 lstTables.OnContextPopup := lstTablesContextPopup; DBGridEh1.OnContextPopup := DBGridEh1ContextPopup; InitHighlighter; //在FormCreate中添加键盘事件 SynEdit1.OnKeyPress := SynEdit1KeyPress; end; procedure TForm1.LoadConnections; begin cbConnections.Items.Clear; cbConnections.Items.Add('连接1: 21 gy_zh_hy_cp_aq_jf_yw_yy_nl_dt_dz_auth_td_gz'); cbConnections.Items.Add('连接2: 22 sc_fz_wd_sz_bi_jk_hl_ys_tj'); cbConnections.Items.Add('连接3: 23 jy_jc_bl_zj'); cbConnections.Items.Add('连接4: 24 jz_br_yj'); cbConnections.Items.Add('连接5: 25 yz_lj_hz_zz_yx'); cbConnections.Items.Add('连接6: 26 fy_yg_hg_wm'); cbConnections.Items.Add('连接7: 27 yp_zl_sm_jh_wl'); cbConnections.Items.Add('连接8: 28 聚合库'); end; procedure TForm1.LoadTables; begin lstTables.Items.Clear; if not UniConnection0.Connected then Exit; try UniQueryTables.Close; // 修改SQL查询,获取lyradb数据库中除public模式外的所有表 UniQueryTables.SQL.Text := 'SELECT table_schema, table_name ' + 'FROM information_schema.tables ' + 'WHERE table_catalog = ''lyradb'' ' + // 指定数据库名 'AND table_schema NOT IN (''public'', ''information_schema'', ''pg_catalog'',''hint_plan'',''lyra'',''profile'',''repack'',''util'') ' + // 排除系统模式 'AND table_schema NOT LIKE ''ceti%'' ' +// 排除系统模式 'AND table_schema NOT LIKE ''grus%'' ' +// 排除系统模式 'AND table_type = ''BASE TABLE'' ' + // 只获取基本表 'ORDER BY table_schema, table_name'; UniQueryTables.Open; while not UniQueryTables.Eof do begin // 显示格式:模式名.表名 lstTables.Items.Add( UniQueryTables.FieldByName('table_schema').AsString + '.' + UniQueryTables.FieldByName('table_name').AsString ); UniQueryTables.Next; end; UniQueryTables.Close; except on E: Exception do ShowMessage('加载表列表失败: ' + E.Message); end; end; procedure TForm1.lstTablesClick(Sender: TObject); begin if lstTables.ItemIndex >= 0 then begin // 加载选定表的所有字段 LoadFields(lstTables.Items[lstTables.ItemIndex]); end; end; procedure TForm1.LoadFields(const TableFullName: string); var SchemaName, TableName: string; DotPos,i: Integer; begin // 解析模式名和表名 DotPos := Pos('.', TableFullName); if DotPos > 0 then begin SchemaName := AnsiQuotedStr(Copy(TableFullName, 1, DotPos-1), '"'); TableName := AnsiQuotedStr(Copy(TableFullName, DotPos+1, MaxInt), '"'); end else begin SchemaName := 'public'; // 默认模式 TableName := AnsiQuotedStr(TableFullName, '"'); end; // 清空字段信息 DBGridEh1.Columns.Clear; // 获取选定表的所有字段信息(包含注释) UniQueryFields.Close; UniQueryFields.SQL.Text := 'SELECT ' + ' c.column_name, ' + ' c.data_type, ' + ' c.column_default, ' + ' c.is_nullable, ' + ' col_description((c.table_schema||''.''||c.table_name)::regclass::oid, c.ordinal_position) as column_comment ' + 'FROM information_schema.columns c ' + 'WHERE c.table_schema = ' + SchemaName + 'AND c.table_name = ' + TableName + 'ORDER BY c.ordinal_position'; UniQueryFields.ParamByName('schema_name').AsString := SchemaName; UniQueryFields.ParamByName('table_name').AsString := TableName; UniQueryFields.Open; // 设置数据源 UniDataSource1.DataSet := UniQueryFields; // 自动添加所有列到DBGridEh DBGridEh1.Columns.AddAllColumns(True); // 然后再限制最大宽度 for i := 0 to DBGridEh1.Columns.Count - 1 do begin DBGridEh1.Columns[i].OptimizeWidth; if DBGridEh1.Columns[i].Width > 200 then DBGridEh1.Columns[i].Width := 200; end; end; procedure TForm1.ConnectToDatabase(Index: Integer); var ConnStr: string; begin UniConnection0.Disconnect; // 设置 Provider 名称 UniConnection0.ProviderName := 'PostgreSQL'; case Index of 0: begin // 连接1 UniConnection0.Server := '192.168.129.21'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 1: begin // 连接2 UniConnection0.Server := '192.168.129.22'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; // 其他连接配置... 2: begin // 连接3 UniConnection0.Server := '192.168.129.23'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 3: begin // 连接4 UniConnection0.Server := '192.168.129.24'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 4: begin // 连接5 UniConnection0.Server := '192.168.129.25'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 5: begin // 连接6 UniConnection0.Server := '192.168.129.26'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 6: begin // 连接7 UniConnection0.Server := '192.168.129.27'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; 7: begin // 连接8 UniConnection0.Server := '192.168.129.28'; UniConnection0.Database := 'lyradb'; UniConnection0.Username := 'lyra_ops'; UniConnection0.Password := 'i48VF69KXwgP'; UniConnection0.Port := 5432; // 明确指定端口 end; end; // 显示连接字符串用于调试 ConnStr := Format('Server=%s;Database=%s;User_ID=%s;Port=%d', [UniConnection0.Server, UniConnection0.Database, UniConnection0.Username, UniConnection0.Port]); StatusBar1.Panels[0].Text := '正在连接: ' + ConnStr; try if not TestNetworkConnection(UniConnection0.Server, 5432) then begin ShowMessage('无法连接到数据库服务器,请检查网络连接'); Exit; end; UniConnection0.Connect; StatusBar1.Panels[0].Text := '已连接到: ' + cbConnections.Items[Index]; // 连接成功后加载表 // 连接成功后重新加载 LoadTables; SynCompletionProposal1.ItemList.Clear; // 清空之前的缓存 LoadDatabaseSchema; except on E: Exception do // ShowMessage('连接失败: ' + E.Message); begin ShowMessage(Format('连接失败:'#13#10'错误: %s'#13#10'连接字符串: %s', [E.Message, ConnStr])); StatusBar1.Panels[0].Text := '连接失败'; end; end; end; procedure TForm1.btnExecuteClick(Sender: TObject); var i: Integer; SQLToExecute: string; begin if not UniConnection0.Connected then begin ShowMessage('请先连接到数据库'); Exit; end; // 判断是否有选中文本 if SynEdit1.SelText <> '' then SQLToExecute := SynEdit1.SelText // 执行选中的SQL else SQLToExecute := SynEdit1.Text; // 执行全部SQL if Trim(SQLToExecute) = '' then begin ShowMessage('请输入SQL语句'); Exit; end; try UniQuery1.Close; UniQuery1.SQL.Text := SQLToExecute; // 判断SQL类型(查询或更新) if (Pos('SELECT', UpperCase(SQLToExecute)) = 1) or (Pos('WITH', UpperCase(SQLToExecute)) = 1) or (Pos('SHOW', UpperCase(SQLToExecute)) = 1) then begin UniQuery1.Open; StatusBar1.Panels[1].Text := '记录数: ' + IntToStr(UniQuery1.RecordCount); // 自动调整列宽 DBGridEh0.Columns.Clear; DBGridEh0.Columns.AddAllColumns(True); for i := 0 to DBGridEh0.Columns.Count - 1 do begin DBGridEh0.Columns[i].OptimizeWidth; if DBGridEh0.Columns[i].Width > 200 then DBGridEh0.Columns[i].Width := 200; end; end else begin // 执行非查询语句 UniQuery1.ExecSQL; StatusBar1.Panels[1].Text := '执行成功,影响行数: ' + IntToStr(UniQuery1.RowsAffected); end; except on E: Exception do ShowMessage('执行SQL失败: ' + E.Message); end; end; procedure TForm1.btnUpdateClick(Sender: TObject); begin if UniQuery1.State in [dsEdit, dsInsert] then UniQuery1.Post; try UniQuery1.ApplyUpdates; ShowMessage('更新成功'); except on E: Exception do ShowMessage('更新失败: ' + E.Message); end; end; procedure TForm1.btnExportExcelClick(Sender: TObject); var // ExpClass: TDBGridEhExportClass; Exp: TDBGridEhExportAsXLSX; Ext: string; i: Integer; SaveDialog1: TSaveDialog; begin if UniQuery1.IsEmpty then begin ShowMessage('没有数据可导出'); Exit; end; SaveDialog1 := TSaveDialog.Create(nil); try SaveDialog1.Filter := 'Excel文件(*.xls)|*.xls|Excel 2007+(*.xlsx)|*.xlsx'; SaveDialog1.DefaultExt := 'xls'; SaveDialog1.InitialDir := '\Desktop\'; SaveDialog1.FileName := '导出数据_' + FormatDateTime('yyyymmddhhnnss', Now); if SaveDialog1.Execute then begin // ExpClass := TDBGridEhExportAsXLS; Exp := TDBGridEhExportAsXLSX.Create; Ext := 'xls'; if Pos('.xlsx', LowerCase(SaveDialog1.FileName)) > 0 then Ext := 'xlsx'; if UpperCase(ExtractFileExt(SaveDialog1.FileName)) <> '.' + UpperCase(Ext) then SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext; // 执行导出 try // 设置DBGridEh的样式 Exp.DBGridEh := DBGridEh0; Exp.DBGridEh.TitleFont := DBGridEh0.TitleFont; Exp.DBGridEh.TitleFont.Name := '宋体'; Exp.DBGridEh.TitleFont.Style := [fsBold]; Exp.DBGridEh.TitleFont.Size := 12; Exp.DBGridEh.TitleParams.Color := clSkyBlue; for i := 0 to Exp.DBGridEh.Columns.Count - 1 do begin Exp.DBGridEh.Columns[i].OptimizeWidth; if Exp.DBGridEh.Columns[i].Width > 200 then Exp.DBGridEh.Columns[i].Width := 200; end; if SameText(Ext, 'xlsx') then begin Exp.ExportToFile(SaveDialog1.FileName, True); end else begin Exp.ExportToFile(SaveDialog1.FileName, True); end; finally Exp.Free; end; // ShowMessage('导出成功: ' + SaveDialog1.FileName); // 假设导出操作已经完成 if MessageDlg('导出成功: ' + SaveDialog1.FileName + #13#10'是否要打开文件?', mtInformation, [mbYes, mbNo], 0, mbNo) = mrYes then begin // 用户点击了"是"(打开文件) ShellExecute(0, 'open', PChar(SaveDialog1.FileName), nil, nil, SW_SHOWNORMAL); end; end; finally SaveDialog1.Free; end; end; procedure TForm1.btnExit1Click(Sender: TObject); begin Form1.Close; end; procedure TForm1.cbConnectionsChange(Sender: TObject); begin ConnectToDatabase(cbConnections.ItemIndex); end; end. 上述代码可以在Delphi XE8中编译成功,但运行后,自动查询提示表名和列名的功能有报错。比如选择连接6连接数据库后,其中有vela_fy.fy_yb_yaopinml等表,预想的是输入vela_fy.后会弹出提示框列出类似vela_fy.fy_yb_yaopinml的所有表名可供选择录入,但实际是弹出了一个空白框,其下方还有应用程序报错弹框提示“List index out of bounds (0)”,请看一下问题出在哪里?要怎么修改?
08-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值