Windows指定Time Server语句0x8 解释

对于指定 Windows Time Server,你可能打以下的语句

w32tm /config /manualpeerlist:NTP_server_IP_Address,0x8 /syncfromflags:MANUAL

0x8是什么意思呢,以下是英文解释

The mode that Windows Time uses to send requests is set by the following registry subkey:

 

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer

If the value of the Enabled entry in this subkey is 1, Windows Time uses symmetric active mode. Otherwise, Windows Time uses client mode.

The 0x8 setting that is referenced in the command in the "Resolution" section sets Windows Time to use client mode.

The valid settings for the mode used with the /manualpeerlist switch include the following:

  • 0x01 - use special poll interval SpecialInterval
  • 0x02 - UseAsFallbackOnly
  • 0x04 - send request as SymmetricActive mode
  • 0x08 - send request as Client mode

假如需要深究什么是SymmetricActive mode 什么是Client mode, 那就需要看原理了,以下是一个参考

http://www.bytefusion.com/products/ntm/pts/3_3modesofoperation.htm




本文转自 VirtualTom 51CTO博客,原文链接:http://blog.51cto.com/virtualtom/755444,如需转载请自行联系原作者

<think>我们首先需要解决两个问题: 1. 详细介绍Microsoft SQL Server 2014中的BULK INSERT语句的参数和用法。 2. 使用Delphi 11将UTF-8格式的二维数组通过BULK INSERT插入到SQL Server数据库表中。 由于BULK INSERT要求数据源是文件,因此我们需要先将二维数组写入一个临时的CSV文件(UTF-8编码),然后使用BULK INSERT从该文件中导入数据。 步骤: 1. 在Delphi中,将二维数组转换为CSV格式的字符串,并保存为UTF-8编码的文本文件。 2. 使用ADO或FDConnection等组件执行BULK INSERT语句指定该文件路径。 注意:SQL Server的BULK INSERT对文件路径有访问权限要求,需要确保SQL Server服务账户有权限读取该文件。 下面详细说明: ### 一、BULK INSERT 参数详解 语法: ```sql BULK INSERT [ [ database_name . ] schema_name . ] table_name FROM &#39;data_file&#39; [ WITH ( [ [ , ] BATCHSIZE = batch_size ] [ [ , ] CHECK_CONSTRAINTS ] [ [ , ] CODEPAGE = { &#39;ACP&#39; | &#39;OEM&#39; | &#39;RAW&#39; | &#39;code_page&#39; } ] [ [ , ] DATAFILETYPE = { &#39;char&#39; | &#39;native&#39; | &#39;widechar&#39; | &#39;widenative&#39; } ] [ [ , ] FIELDTERMINATOR = &#39;field_terminator&#39; ] [ [ , ] FIRSTROW = first_row ] [ [ , ] FIRE_TRIGGERS ] [ [ , ] FORMATFILE = &#39;format_file_path&#39; ] [ [ , ] KEEPIDENTITY ] [ [ , ] KEEPNULLS ] [ [ , ] KILOBYTES_PER_BATCH = kilobytes_per_batch ] [ [ , ] LASTROW = last_row ] [ [ , ] MAXERRORS = max_errors ] [ [ , ] ORDER ( { column [ ASC | DESC ] } [ ,...n ] ) ] [ [ , ] ROWS_PER_BATCH = rows_per_batch ] [ [ , ] ROWTERMINATOR = &#39;row_terminator&#39; ] [ [ , ] TABLOCK ] [ [ , ] ERRORFILE = &#39;file_name&#39; ] ) ] ``` 常用参数说明: 1. **BATCHSIZE**:指定每批导入的行数。默认是整个文件。 2. **CHECK_CONSTRAINTS**:指定在导入期间检查表约束。默认情况下,忽略约束。 3. **CODEPAGE**:指定文件中数据的代码页。对于UTF-8文件,使用`CODEPAGE=&#39;65001&#39;`。 4. **DATAFILETYPE**:指定文件类型。对于UTF-8文本文件,使用`DATAFILETYPE=&#39;char&#39;`;对于Unicode(UTF-16)文件,使用`&#39;widechar&#39;`。注意:UTF-8文件应使用`char`并配合`CODEPAGE=&#39;65001&#39;`。 5. **FIELDTERMINATOR**:指定列分隔符,默认为制表符`\t`。对于CSV文件,通常为逗号`&#39;,&#39;`。 6. **FIRSTROW**:指定开始导入的第一行的行号(从1开始计数)。如果文件有标题行,可以设置为2跳过标题。 7. **FIRE_TRIGGERS**:指定是否触发插入触发器。默认不触发。 8. **FORMATFILE**:指定格式文件的路径,用于非标准格式的文件(如列顺序不一致)。 9. **KEEPNULLS**:指定在导入过程中,空列应保留NULL值,而不是使用列的默认值。 10. **LASTROW**:指定导入的最后一行行号。 11. **MAXERRORS**:指定允许的最大错误数,超过则终止导入。默认为10。 12. **ROWTERMINATOR**:指定行终止符。在Windows中通常为`&#39;\r\n&#39;`。 13. **TABLOCK**:在导入期间获取表级锁,可以提高性能。 14. **ERRORFILE**:指定错误文件的路径,用于记录格式错误无法导入的行。 ### 二、Delphi 11实现步骤 假设我们有一个二维数组`Data: TArray<TArray<string>>`,其中每个内层数组代表一行,每行有两个元素(对应两列)。 步骤: 1. 将二维数组转换为CSV格式的字符串(使用逗号分隔列,换行符分隔行)。 2. 将字符串保存为UTF-8编码的临时文件(注意:Delphi默认的字符串是Unicode,所以保存为UTF-8需要处理)。 3. 构造BULK INSERT语句指定临时文件路径和参数(特别是CODEPAGE=&#39;65001&#39;)。 4. 使用ADOQuery或FDQuery执行该SQL语句。 示例代码(Delphi 11): ```delphi uses System.Classes, System.SysUtils, Data.DB, FireDAC.Comp.Client, System.IOUtils; procedure InsertDataViaBulkInsert(Connection: TFDConnection; const Data: TArray<TArray<string>>); var CSV: TStringList; I: Integer; TempFileName: string; SQL: string; begin // 创建CSV内容 CSV := TStringList.Create; try for I := 0 to High(Data) do begin // 每行两个元素,用逗号分隔 if Length(Data[I]) >= 2 then CSV.Add(Format(&#39;"%s","%s"&#39;, [Data[I][0], Data[I][1]])); end; // 创建临时文件(使用系统临时目录) TempFileName := TPath.GetTempFileName; // 将CSV内容保存为UTF-8文件(带BOM) CSV.SaveToFile(TempFileName, TEncoding.UTF8); // 构造BULK INSERT语句 SQL := &#39;BULK INSERT JR..time_old &#39; + // 数据库名..表名,如果JR是数据库名,则写成[JR].dbo.time_old &#39;FROM &#39;&#39;&#39; + TempFileName + &#39;&#39;&#39; &#39; + &#39;WITH ( &#39; + &#39;CODEPAGE = &#39;&#39;65001&#39;&#39;, &#39; + // UTF-8编码 &#39;DATAFILETYPE = &#39;&#39;char&#39;&#39;, &#39; + // 文本文件 &#39;FIELDTERMINATOR = &#39;&#39;,&#39;&#39;, &#39; + // 列分隔符为逗号,注意:如果字段中包含逗号,需要用双引号括起来 &#39;ROWTERMINATOR = &#39;&#39;\n&#39;&#39;, &#39; + // 行终止符,这里使用\n(因为TStringList默认使用当前系统的行结束符,但保存为文本时是系统默认,这里我们指定为\n,实际在Windows中可能是\r\n,但BULK INSERT也支持\n) &#39;KEEPNULLS, &#39; + &#39;FIRSTROW = 1 &#39; + // 从第一行开始(没有标题行) &#39;)&#39;; // 执行SQL Connection.ExecSQL(SQL); finally CSV.Free; // 删除临时文件 if FileExists(TempFileName) then DeleteFile(TempFileName); end; end; ``` 注意: - 如果字段内容包含逗号或换行符,需要将字段用双引号括起来,并且双引号内的双引号用两个双引号表示(CSV标准)。上面的Format函数中已经用双引号将每个字段括起来了。 - 行终止符:在Windows中通常为`\r\n`,但BULK INSERT也支持`\n`。上面我们使用了`\n`,因为TStringList在保存时默认使用当前系统的行结束符(在Windows中是`\r\n`),但我们在ROWTERMINATOR中指定为`&#39;\n&#39;`可能不匹配。因此,我们可以改为使用`ROWTERMINATOR = &#39;&#39;0x0a&#39;&#39;`(十六进制表示换行)或者使用`ROWTERMINATOR = &#39;&#39;&#39; + #10 + &#39;&#39;&#39;&#39;`(在Delphi字符串中表示为`#13#10`,但实际保存的文件是`\r\n`,所以应该指定为`&#39;\r\n&#39;`)。因此,修改如下: 修正行终止符部分: 由于TStringList在保存到文件时,在Windows平台下默认使用`\r\n`作为行结束符,所以ROWTERMINATOR应该设置为`&#39;\r\n&#39;`。但是,在SQL语句中表示回车换行需要写成`&#39;\r\n&#39;`,并且在字符串中需要转义单引号,所以: ```delphi SQL := &#39;BULK INSERT JR..time_old &#39; + &#39;FROM &#39;&#39;&#39; + TempFileName + &#39;&#39;&#39; &#39; + &#39;WITH ( &#39; + &#39;CODEPAGE = &#39;&#39;65001&#39;&#39;, &#39; + &#39;DATAFILETYPE = &#39;&#39;char&#39;&#39;, &#39; + &#39;FIELDTERMINATOR = &#39;&#39;,&#39;&#39;, &#39; + &#39;ROWTERMINATOR = &#39;&#39;&#39; + #13#10 + &#39;&#39;&#39;, &#39; + // 注意:这里用两个单引号表示字符串中的单引号,然后中间是转义后的行终止符 &#39;KEEPNULLS, &#39; + &#39;FIRSTROW = 1 &#39; + &#39;)&#39;; ``` 但是,这样写会使得SQL语句中的行终止符部分变成`ROWTERMINATOR = &#39;回车换行&#39;,`,这显然不对。正确做法是使用转义字符表示`\r\n`,即: &#39;ROWTERMINATOR = &#39;&#39;&#39; + &#39;\r\n&#39; + &#39;&#39;&#39;, &#39; 但是,在SQL语句中,我们传递的是字符串,所以应该用两个单引号表示一个单引号,而`\r\n`是普通字符,所以直接写即可。但是,在BULK INSERT语句中,字符串内的`\r\n`会被解释为回车换行。因此,我们可以这样写: &#39;ROWTERMINATOR = &#39;&#39;\r\n&#39;&#39;, &#39; 所以,完整的SQL字符串构造: ```delphi SQL := &#39;BULK INSERT JR..time_old &#39; + &#39;FROM &#39;&#39;&#39; + TempFileName + &#39;&#39;&#39; &#39; + &#39;WITH ( &#39; + &#39;CODEPAGE = &#39;&#39;65001&#39;&#39;, &#39; + // UTF-8编码 &#39;DATAFILETYPE = &#39;&#39;char&#39;&#39;, &#39; + // 文本文件 &#39;FIELDTERMINATOR = &#39;&#39;,&#39;&#39;, &#39; + // 列分隔符为逗号 &#39;ROWTERMINATOR = &#39;&#39;\r\n&#39;&#39;, &#39; + // 行终止符 &#39;KEEPNULLS, &#39; + &#39;FIRSTROW = 1 &#39; + // 从第一行开始(没有标题行) &#39;)&#39;; ``` 另外,如果表在特定的架构下(如dbo),则应该写为`[JR].[dbo].[time_old]`。 权限问题:临时文件可能位于临时目录,需要确保SQL Server服务账户有权限读取该目录。如果权限不足,可以考虑将临时文件保存到SQL Server有权限访问的目录(如SQL Server数据目录或共享目录)。 ### 三、示例调用 假设我们有一个二维数组: ```delphi var Data: TArray<TArray<string>>; begin SetLength(Data, 2); Data[0] := [&#39;值1&#39;, &#39;值2&#39;]; Data[1] := [&#39;值3&#39;, &#39;值4&#39;]; InsertDataViaBulkInsert(FDConnection1, Data); end; ``` 注意:如果数据量很大,生成CSV字符串可能会占用较多内存,可以考虑使用流式写入文件。 如果遇到权限问题,参考引用[2]中的方法,将临时文件保存到SQL Server的Data目录(通常有权限)或者调整权限。 ### 相关问题 1. **如何跳过BULK INSERT导入过程中的错误?** 2. **Delphi中如何将二维数组导出为CSV文件(UTF-8编码)?** 3. **SQL Server BULK INSERT导入时出现代码页转换错误如何解决?** 4. **如何提高BULK INSERT导入大量数据的性能?** 引用说明: - 引用[1]中提到了使用存储过程循环插入,但这里我们使用BULK INSERT更高效。 - 引用[2]提到了附加数据库权限问题,类似地,BULK INSERT也需要文件访问权限。 - 引用[3]提醒了SQL注入问题,但我们的方法中,SQL语句是拼接文件路径,而文件路径是临时生成的,相对安全(但也要注意文件名中不能有特殊字符,这里使用系统生成的临时文件名是安全的)。 注意:在构造SQL语句时,我们使用了临时文件名,该文件名是系统生成的,不包含用户输入,因此不会存在SQL注入问题。 如果遇到问题,可以检查SQL Server错误日志,或者使用ERRORFILE参数记录错误行。</think>### Microsoft SQL Server 2014 BULK INSERT 参数详解 #### 核心语法 ```sql BULK INSERT [database].[schema].[table] FROM &#39;data_file_path&#39; WITH ( [parameter = value], ... ); ``` #### 完整参数列表及解释 1. **BATCHSIZE** - 每批插入行数:`BATCHSIZE = 1000` - 优化大文件导入性能 2. **CHECK_CONSTRAINTS** - 导入时检查约束:`CHECK_CONSTRAINTS` - 默认忽略约束验证 3. **CODEPAGE** - **UTF-8文件必须设置**:`CODEPAGE = &#39;65001&#39;` - 其他选项:`ACP`(ANSI), `OEM`(系统默认) 4. **DATAFILETYPE** - 文件类型:`char`(文本), `widechar`(Unicode) - UTF-8推荐:`DATAFILETYPE = &#39;char&#39;` 5. **FIELDTERMINATOR** - 列分隔符:`FIELDTERMINATOR = &#39;,&#39;` - 二维数组常用逗号分隔 6. **FIRSTROW** - 起始行号:`FIRSTROW = 2` - 跳过标题行 7. **FIRE_TRIGGERS** - 触发插入触发器:`FIRE_TRIGGERS` - 默认不触发 8. **FORMATFILE** - 格式文件路径:`FORMATFILE = &#39;C:\format.xml&#39;` - 定义列映射规则 9. **KEEPIDENTITY** - 保留标识列值:`KEEPIDENTITY` 10. **KEEPNULLS** - 保留空值:`KEEPNULLS` 11. **ROWTERMINATOR** - 行终止符:`ROWTERMINATOR = &#39;\r\n&#39;` - Windows系统推荐 12. **TABLOCK** - 表级锁:`TABLOCK` - 提升导入性能 13. **ERRORFILE** - 错误日志:`ERRORFILE = &#39;C:\errors.log&#39;` 14. **MAXERRORS** - 最大容错数:`MAXERRORS = 10` - 超过则终止导入 --- ### Delphi 11 实现 UTF-8 二维数组导入 #### 实现步骤 1. **准备数据文件** 将二维数组转换为CSV格式并保存为UTF-8文件: ```delphi var CSV: TStringList; I: Integer; begin CSV := TStringList.Create; try CSV.Text := &#39;c_tr1,c_tr2&#39; + sLineBreak; // 列标题 for I := 0 to High(ctime) do CSV.Add(Format(&#39;%s,%s&#39;, [ctime[I][0], ctime[I][1]])); CSV.SaveToFile(&#39;C:\temp\data.csv&#39;, TEncoding.UTF8); finally CSV.Free; end; end; ``` 2. **执行BULK INSERT** 使用TFDConnection执行SQL命令: ```delphi procedure BulkInsertData(Connection: TFDConnection); var SQL: string; begin SQL := &#39;BULK INSERT JR.dbo.time_old &#39; + &#39;FROM &#39;&#39;C:\temp\data.csv&#39;&#39; &#39; + &#39;WITH ( &#39; + &#39;CODEPAGE = &#39;&#39;65001&#39;&#39;, &#39; + &#39;DATAFILETYPE = &#39;&#39;char&#39;&#39;, &#39; + &#39;FIELDTERMINATOR = &#39;&#39;,&#39;&#39;, &#39; + &#39;ROWTERMINATOR = &#39;&#39;\r\n&#39;&#39;, &#39; + &#39;FIRSTROW = 2, &#39; + // 跳过标题行 &#39;KEEPNULLS, &#39; + &#39;TABLOCK &#39; + &#39;)&#39;; Connection.ExecSQL(SQL); end; ``` 3. **权限处理** 参考引用[2]解决权限问题: - 将文件放在SQL Server的`DATA`目录 - 授予SQL Server服务账户文件读写权限 - 修改服务登录身份为`Local Service` #### 关键注意事项 1. **UTF-8编码处理** - 文件必须包含BOM头(Delphi自动添加) - 必须设置`CODEPAGE=65001` 2. **特殊字符处理** 若数据包含逗号,需用引号包裹字段: ```delphi CSV.Add(Format(&#39;"%s","%s"&#39;, [ctime[I][0], ctime[I][1]])); ``` 3. **性能优化** - 使用`TABLOCK`减少锁竞争 - 设置`BATCHSIZE=5000`分批提交 - 导入前禁用索引 4. **错误处理** ```sql ERRORFILE = &#39;C:\errors.log&#39;, MAXERRORS = 100 ``` --- ### 替代方案:参数化插入 若数据量小,推荐参数化插入防止SQL注入(参考引用[3]): ```delphi procedure SafeInsert(Connection: TFDConnection); var Query: TFDQuery; I: Integer; begin Query := TFDQuery.Create(nil); try Query.Connection := Connection; Query.SQL.Text := &#39;INSERT INTO time_old (c_tr1, c_tr2) VALUES (:val1, :val2)&#39;; for I := 0 to High(ctime) do begin Query.ParamByName(&#39;val1&#39;).AsString := ctime[I][0]; Query.ParamByName(&#39;val2&#39;).AsString := ctime[I][1]; Query.ExecSQL; end; finally Query.Free; end; end; ``` --- ### 相关问题 1. **如何解决BULK INSERT导入时的权限拒绝错误?** 2. **Delphi中如何验证UTF-8文件的BOM头?** 3. **大批量数据导入时如何优化Delphi内存使用?** 4. **SQL Server 2014是否支持直接导入JSON格式数据?** [^1]: 存储过程循环插入示例 [^2]: SQL Server文件权限解决方案 [^3]: 参数化插入防SQL注入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值