亚洲必赢手机入口(iOS, Swift)十六进制转Data,十六进制转整形,Data转String分享MSSQL、MySql、Oracle的死数目批量导入方法及编程手法细节,mssqloracle
Swift
分享MSSQL、MySql、Oracle的不可开交数量批量导入方法与编程手法细节,mssqloracle
整型转 Data:
接口
/// Initialize a `Data` with the contents of an Array.
///
/// - parameter bytes: An array of bytes to copy.
public init(bytes: [UInt8])
使用
let data = Data(bytes: [11, 011, 0x11])
1:MSSQL
十六前行制字符串 转 Data:
//将十六进制字符串转化为 Data
func data(from hexStr: String) -> Data {
let bytes = self.bytes(from: hexStr)
return Data(bytes: bytes)
}
// 将16进制字符串转化为 [UInt8]
// 使用的时候直接初始化出 Data
// Data(bytes: Array<UInt8>)
func bytes(from hexStr: String) -> [UInt8] {
assert(hexStr.count % 2 == 0, "输入字符串格式不对,8位代表一个字符")
var bytes = [UInt8]()
var sum = 0
// 整形的 utf8 编码范围
let intRange = 48...57
// 小写 a~f 的 utf8 的编码范围
let lowercaseRange = 97...102
// 大写 A~F 的 utf8 的编码范围
let uppercasedRange = 65...70
for (index, c) in hexStr.utf8CString.enumerated() {
var intC = Int(c.byteSwapped)
if intC == 0 {
break
} else if intRange.contains(intC) {
intC -= 48
} else if lowercaseRange.contains(intC) {
intC -= 87
} else if uppercasedRange.contains(intC) {
intC -= 55
} else {
assertionFailure("输入字符串格式不对,每个字符都需要在0~9,a~f,A~F内")
}
sum = sum * 16 + intC
// 每两个十六进制字母代表8位,即一个字节
if index % 2 != 0 {
bytes.append(UInt8(sum))
sum = 0
}
}
return bytes
}
SQL语法篇:
BULK INSERT
[ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ]
FROM 'data_file'
[ WITH
(
[ [ , ] BATCHSIZE = batch_size ]
[ [ , ] CHECK_CONSTRAINTS ]
[ [ , ] CODEPAGE = { 'ACP' | 'OEM' | 'RAW' | 'code_page' } ]
[ [ , ] DATAFILETYPE =
{ 'char' | 'native'| 'widechar' | 'widenative' } ]
[ [ , ] FIELDTERMINATOR = 'field_terminator' ]
[ [ , ] FIRSTROW = first_row ]
[ [ , ] FIRE_TRIGGERS ]
[ [ , ] FORMATFILE = 'format_file_path' ]
[ [ , ] 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 = 'row_terminator' ]
[ [ , ] TABLOCK ]
[ [ , ] ERRORFILE = 'file_name' ]
)]
SQL示例:
bulk insert 表名 from 'D:\mydata.txt'
with
(fieldterminator=',',
rowterminator='\n',
check_constraints)
select * from 表名
由于C#供了SqlBulkCopy,所以非DBA的我们,更多见面由此序来调用:
Data 转 String:
func string(from data: Data) -> String {
return String(format: "%@", data as CVarArg)
}
C#代码篇:
C#代码调用示例及细节,以下代码摘录自CYQ.Data:
using (SqlBulkCopy sbc = new SqlBulkCopy(con, (keepID ? SqlBulkCopyOptions.KeepIdentity : SqlBulkCopyOptions.Default) | SqlBulkCopyOptions.FireTriggers, sqlTran))
{
sbc.BatchSize = 100000;
sbc.DestinationTableName = SqlFormat.Keyword(mdt.TableName, DalType.MsSql);
sbc.BulkCopyTimeout = AppConfig.DB.CommandTimeout;
foreach (MCellStruct column in mdt.Columns)
{
sbc.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
sbc.WriteToServer(mdt);
}
有5个细节:
1:事务:
设若一味是单科事务,构造函数可以是链接字符串。
假设需要和标合成一个事务(比如事先去,再插入,这在和一个事情中)
即待团结组织Connection对象以及Transaction,在前后文中传递来处理。
2:插入是否引发触发器
通过SqlBulkCopyOptions.FireTriggers 引入
3:其它:批量数、超时时间、是否刻画副主键ID。
十六进制 转 整形:
func integer(from hexStr: String) -> Int {
var sum = 0
// 整形的 utf8 编码范围
let intRange = 48...57
// 小写 a~f 的 utf8 的编码范围
let lowercaseRange = 97...102
// 大写 A~F 的 utf8 的编码范围
let uppercasedRange = 65...70
for c in hexStr.utf8CString {
var intC = Int(c.byteSwapped)
if intC == 0 {
break
} else if intRange.contains(intC) {
intC -= 48
} else if lowercaseRange.contains(intC) {
intC -= 87
} else if uppercasedRange.contains(intC) {
intC -= 55
} else {
assertionFailure("输入字符串格式不对,每个字符都需要在0~9,a~f,A~F内")
}
sum = sum * 16 + intC
}
return sum
}
也许引发的数据库Down机的情况:
当历史的经过遭到,我遇上了之一个大坑是:
当数码的长过长,数据的字段过少,产生多少二进制截断时,数据库服务还停掉了(也许是特例,也许不是)。
所以小心使用,尽力做好针对性标数据做好数据长度验证。
2:MySql
有关MySql的批量,这是同样段落悲催的旧闻,有几乎个坑,直到今天,才意识并解决了。
SQL语法篇:
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'data.txt'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[FIELDS
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char' ]
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number LINES]
[(col_name_or_user_var,...)]
[SET col_name = expr,...)]
示例篇:
LOAD DATA LOCAL INFILE 'C:\\Users\\cyq\\AppData\\Local\\Temp\\BulkCopy.csv' INTO TABLE `BulkCopy` CHARACTER SET utf8 FIELDS TERMINATED BY '$,$' LINES TERMINATED BY '
' (`ID`,`Name`,`CreateTime`,`Sex`)
尽管如此MySql.Data.dll 提供了MySqlBulkLoader,但是关押源码只是可怜成了只Load
Data 并就此ADO.NET执行,
主导大坑的变迁*.csv数据文件的竟没有提供,所以自己生成语句并施行就好了,不需要因此它。
C#代码篇:
以下代码摘自CYQ.Data,是相同段落今天才修正好的代码:
private static string MDataTableToFile(MDataTable dt, bool keepID, DalType dalType)
{
string path = Path.GetTempPath() + dt.TableName + ".csv";
using (StreamWriter sw = new StreamWriter(path, false, new UTF8Encoding(false)))
{
MCellStruct ms;
string value;
foreach (MDataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
#region 设置值
ms = dt.Columns[i];
if (!keepID && ms.IsAutoIncrement)
{
continue;
}
else if (dalType == DalType.MySql && row[i].IsNull)
{
sw.Write("\\N");//Mysql用\N表示null值。
}
else
{
value = row[i].ToString();
if (ms.SqlType == SqlDbType.Bit)
{
int v = (value.ToLower() == "true" || value == "1") ? 1 : 0;
if (dalType == DalType.MySql)
{
byte[] b = new byte[1];
b[0] = (byte)v;
value = System.Text.Encoding.UTF8.GetString(b);//mysql必须用字节存档。
}
else
{
value = v.ToString();
}
}
else
{
value = value.Replace("\\", "\\\\");//处理转义符号
}
sw.Write(value);
}
if (i != dt.Columns.Count - 1)//不是最后一个就输出
{
sw.Write(AppConst.SplitChar);
}
#endregion
}
sw.WriteLine();
}
}
if (Path.DirectorySeparatorChar == '\\')
{
path = path.Replace(@"\", @"\\");
}
return path;
}
如上代码是发出一个csv文件,用于受调用,有星星点点独中心的坑,费了我不少年华:
1:Bit类型数据导不入?
2:第1执行数据自增ID被重置为1?
立刻半个问题,网上搜不到答案,放纵到今日,觉的当解决了,然后就管其解决了。
缓解之思路是这般的:
A:先用Load Data OutFile导出一个文本,再用Load Data InFile导入文本。
平等开始自己用记事本打开看了一晃,又顺手Ctrl+S了瞬间,结果发现题目及自身之等同,让我难以置信竟然不支持?
以至于今天,重新导出,中间不扣了,直接导入,发现它们还是同时健康的,于是,思维一样转:
B:把自己变的文本及指令产生的公文,进行了十六进制比对,结果发现:
Bit类型自己别的之多寡:是0,1,在十六迈入制下显示是30、31。
命令产生的数以十六进制是00、01,查了产资料,发现MySql的Bit存档的Bit是二进制。
于是,把0,1于是字节表示,再转字符串,再存档,就哼了。
乃这样一截代码有了(网上的DataTable转CSV代码都是绝非处理的,都无知情他们是怎么跑的,难道都无定义Bit类型?):
if (ms.SqlType == SqlDbType.Bit)
{
int v = (value.ToLower() == "true" || value == "1") ? 1 : 0;
if (dalType == DalType.MySql)
{
byte[] b = new byte[1];
b[0] = (byte)v;
value = System.Text.Encoding.UTF8.GetString(b);//mysql必须用字节存档。
}
else
{
value = v.ToString();
}
}
此外关于Null值,用\N表示。
化解了第一独问题,剩下哪怕是第二个问题了,为什么第一个行代码的主键会叫置为1?
要比对十六进制,结果惊人的发现:
凡是BOM头,让它错识别了第一只主键值,所以受忽视主键,用了第1独自增值1替了。
这吗诠释了为什么而还保存之数还有Bug的原故。
乃,解决之不二法门就是是StreaWrite的下,不生成BOM头,怎么处理也?
遂就闹了以下的代码:
using (StreamWriter sw = new StreamWriter(path, false, new UTF8Encoding(false)))
{
...................
}
经New一个Encoding,并点名参数为false,替代我们如常的System.Text.Encoding.UTF8Encoding。
这些细节颇隐秘,不说你都猜不道。。。
3:Oracle
SQL语法篇
LOAD[DATA]
[ { INFILE | INDDN } {file | * }
[STREAM | RECORD | FIXED length [BLOCKSIZE size]|
VARIABLE [length] ]
[ { BADFILE | BADDN } file ]
{DISCARDS | DISCARDMAX} integr ]
[ {INDDN | INFILE} . . . ]
[ APPEND | REPLACE | INSERT ]
[RECLENT integer]
[ { CONCATENATE integer |
CONTINUEIF { [THIS | NEXT] (start[: end])LAST }
Operator { 'string' | X 'hex' } } ]
INTO TABLE [user.]table
[APPEND | REPLACE|INSERT]
[WHEN condition [AND condition]...]
[FIELDS [delimiter] ]
(
column {
RECNUM | CONSTANT value |
SEQUENCE ( { integer | MAX |COUNT} [, increment] ) |
[POSITION ( { start [end] | * [ + integer] }
) ]
datatype
[TERMINATED [ BY ] {WHITESPACE| [X] 'character' } ]
[ [OPTIONALLY] ENCLOSE[BY] [X]'charcter']
[NULLIF condition ]
[DEFAULTIF condotion]
}
[ ,...]
)
以上配置存档成一个CTL文件,再由以下的吩咐调用:
Sqlldr userid=用户名/密码@数据库 control=文件名.ctl
C#语法篇:
.NET里大概有三种操作Oracle的招:
1:System.Data.OracleClient
(需要安装客户端)没有带批量智(还区分x86和x64)。
2:Oracle.DataAccess (需要装客户端)带批量措施(也区分x86与x64)。
3:Oracle.ManagedDataAccess
(不待装客户端)没带批量方法(不区分x86及x64,但就支持.NET
4.0要上述)
Oracle.DataAccess
带的批量方让:OracleBulkCopy,由于下办法及SqlBulkCopy几乎一致,就非介绍了。
如果调用程序所当的服务器安装了Oracle客户端,可以进行以下方法的调用:
流程如下:
1:产生*.cvs数据文件,见MySql中的代码,一样用底。
2:产生*.ctl控制文件,把变化的Load Data 语句存档成一个*.ctl文件即可。
3:用sqlidr.exe执行CTL文件,这里悲催的一点是,不可知用ADO.NET调用,只能用经过调用,所以,这个批量只能单独行使。
调用进程的有关代码:
bool hasSqlLoader = false;
private bool HasSqlLoader() //检测是否安装了客户端。
{
hasSqlLoader = false;
Process proc = new Process();
proc.StartInfo.FileName = "sqlldr";
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
return hasSqlLoader;
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!hasSqlLoader)
{
hasSqlLoader = e.Data.StartsWith("SQL*Loader:");
}
}
//已经实现,但没有事务,所以暂时先不引入。
private bool ExeSqlLoader(string arg)
{
try
{
Process proc = new Process();
proc.StartInfo.FileName = "sqlldr";
proc.StartInfo.Arguments = arg;
proc.Start();
proc.WaitForExit();
return true;
}
catch
{
}
return false;
}
总结:
乘势大数据的推广,数据之中的批量移动必然越来频繁的叫提到,所以不管是故SQL脚本,还是好写代码,或是用DBImport工具,都将化必需技能有了!
鉴于此,分享一下自身于即时同片费过的力和填了之坑,供大家参考!
http://www.bkjia.com/C\_jc/1166848.htmlwww.bkjia.comtruehttp://www.bkjia.com/C\_jc/1166848.htmlTechArticle分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节,mssqloracle
1:MSSQL SQL语法篇: BULK INSERT [ database_name . [ schema_name ]
. | schema_nam…