浏览 21254 次
锁定老帖子 主题:Python读取大文件并插入数据库
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2013-01-27
最后修改:2013-02-01
查看了手册open方法,首先想到了seek()方法,和fread()方法读到一段内容来执行插入。 大概说一下方法吧。 一 取数据 取一段内容,以回车(\n)分隔内容为数据,批量插入数据库 如要读取文件内容如下: abcd efgh ijkl mnop 按13个字符取内容 root_path = os.path.abspath('./') + os.sep f = open(root_path + 'file/pass.txt', 'r') f.seek(0) line = f.read(13) #从文件中读取一段内容 输出如下:(回车[\n]占一个字符) abcd efgh ijk 转换为数组后 L = ['abcd', 'efgh', 'ijk'] 此时插入数据库内容为 ['abcd', 'efgh'] 将最后一条数据缓存 t = L.pop() 下一次循环得到数组为 L = ['l', 'mnop'] 此时将第一条数据和缓存的数据合并 L[0] = t + L[0] 并缓存数组最后一条数据 二 插入数据 插入数据,使用批量插入 最开始的时候我拼好sql语句如:INSERT INTO XX(`a`) VALUES(1),(2),(3)... 然后调用mysql-python的方法 sql = 'INSERT INTO XX(`a`) VALUES(1),(2),(3)' conn = mysql.connector.connect(host='127.0.0.1', database='xxx', user='xxx', password='xxx') conn.cursor().execute(sql) 结果执行了大概2万多就报Lost connection to MySQL server错误了。后来我看mysql-python里面的代码原来批量插入数据有封装好的方法是 data = [ ('Jane','555-001'), ('Joe', '555-001'), ('John', '555-003') ] stmt = "INSERT INTO employees (name, phone) VALUES (%s,%s)" cursor.executemany(stmt, data) 注意以上两点后,上代码: #encoding:utf-8 ''' Created on 2013-1-27 @author: JinHanJiang ''' ''' create table CREATE TABLE `Passwords` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id主键', `pass` varchar(64) NOT NULL COMMENT '密码', `md5` varchar(32) DEFAULT NULL COMMENT '32位md5值', PRIMARY KEY (`id`), UNIQUE KEY `pass` (`pass`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='密码' ''' import os import re import time from datetime import datetime import hashlib import mysql.connector import random root_path = os.path.abspath('./') + os.sep f = open(root_path + 'file/f1.txt', 'r') fields = ['pass', 'md5'] def writeDB(params): conn = cur = None try: fields = '(`' + '`, `'.join(params['fields']) + '`)' stmt = "INSERT IGNORE INTO Passwords"+fields+" VALUES (%s,%s)" conn = mysql.connector.connect(host='127.0.0.1', database='password', user='root', password='admin') cur = conn.cursor() cur.executemany(stmt, params['datas']) except mysql.connector.Error as e: print e finally: if cur: cur.close() if conn: conn.commit() #如果数据库表类型是Innodb记的带个参数 conn.close() pos = 0 step = buff = 1024 * 1024 last = '' dstart = datetime.now() print "Program Start At: " + dstart.strftime('%Y-%m-%d %H:%M:%S') while 1: f.seek(pos) line = f.read(buff) #从文件中读取一段内容 datas = [] if not line: if '' is not last: data = (last, hashlib.md5(last).hexdigest().upper()) datas.append(data) params = {'fields': fields, 'datas': datas} writeDB(params) break; #如果内容为空跳出循环 pos += step #计算取下一段内容长度 lines = re.split("\n", line) #以回车(\n)分隔内容到数组中 lines[0] = str(last) + str(lines[0]) last = lines.pop() #将数组最后一条数据剔除,并存到last变量中,到下次循环再处理 for lin in lines: lin = lin.rstrip() #去除内容末尾的回车字符 if not lin: continue data = (lin, hashlib.md5(lin).hexdigest().upper()) datas.append(data) #封装内容 if len(datas) > 0: params = {'fields': fields, 'datas': datas} writeDB(params) time.sleep(random.random()) #让Cpu随机休息0 <= n < 1.0 s f.close() dend = datetime.now() print "Program End At:%s Time span %s"%(dend.strftime('%Y-%m-%d %H:%M:%S'), dend - dstart); 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2013-01-29
最后修改:2013-01-29
代码太长了。。。。,一条一条插就报错,批量插就不报错?你这个读文件的写法不是PYTHON 写法
|
|
返回顶楼 | |
发表时间:2013-01-29
wangyu.gg 写道 代码太长了。。。。,一条一条插就报错,批量插就不报错?你这个读文件的写法不是PYTHON 写法
可能是我没说清楚。 sql语句如果是:INSERT INTO XX(`a`) VALUES(1),(2),(3)...这样的格式调用execute(sql)插入大概到2万行条记录就报错了。 我用的python2.7.3代码运行正常 |
|
返回顶楼 | |
发表时间:2013-01-31
读文件有readlines,带参数可以限制读取字节数,
光执行sql,不commit那不报错才怪,数据库开的缓存区有限度 用java写入库一般都要exebatch然后commit,python写一样也要commit 用mysql写不写数组效果跟一条一条效果应该是一样一样的,这个可能是mysqldb的问题也可能mysql本身对这种方式支持不好, 数组加速在连接oracle效果才明显,数组有65535的限制, 一般定义不超过5万的数组是没问题的,越接近65535越容易出错,超过了肯定出错 |
|
返回顶楼 | |
发表时间:2013-02-01
oaklet 写道 读文件有readlines,带参数可以限制读取字节数,
光执行sql,不commit那不报错才怪,数据库开的缓存区有限度 用java写入库一般都要exebatch然后commit,python写一样也要commit 用mysql写不写数组效果跟一条一条效果应该是一样一样的,这个可能是mysqldb的问题也可能mysql本身对这种方式支持不好, 数组加速在连接oracle效果才明显,数组有65535的限制, 一般定义不超过5万的数组是没问题的,越接近65535越容易出错,超过了肯定出错 我用的表结构类型是MyISMA,不带事务的。 如果是Innodb确实在插入后要conn.commit()一下。要不然数据是插不进去的。不过也没报错。 |
|
返回顶楼 | |
发表时间:2013-02-01
最后修改:2013-02-01
jinhanjiang 写道 oaklet 写道 读文件有readlines,带参数可以限制读取字节数,
光执行sql,不commit那不报错才怪,数据库开的缓存区有限度 用java写入库一般都要exebatch然后commit,python写一样也要commit 用mysql写不写数组效果跟一条一条效果应该是一样一样的,这个可能是mysqldb的问题也可能mysql本身对这种方式支持不好, 数组加速在连接oracle效果才明显,数组有65535的限制, 一般定义不超过5万的数组是没问题的,越接近65535越容易出错,超过了肯定出错 我用的表结构类型是MyISMA,不带事务的。 如果是Innodb确实在插入后要conn.commit()一下。要不然数据是插不进去的。不过也没报错。 你确定你用的mysql驱动没有这个限制?说不定驱动也会做这个commit的操作,只不过是缓存到内存了。 ps一下,这个python代码写的太长了。。 这么简单的需求应该几十行就够了吧 |
|
返回顶楼 | |
发表时间:2013-06-01
思路是对的
通过中间文件入库 如果是db to db ,例如mysql to mysql 效率性能可能就不好了 |
|
返回顶楼 | |