我的文件格式如下:
Table1; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...
\n
Table2; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...
\n
Table3; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...
从TableX标题之后的下一行开始并以空行分隔符结束的每批记录大约为700-800行。
需要将每批此类行(rec_xyz
...)导入批次标题中指示的相关 MyISAM 表名称(TableX
)< / p>
我熟悉使用shell命令将流传递到LOAD DATA命令的选项。
我对简单的java snipet代码很感兴趣,它会解析这个文件并且每次为一批记录执行LOAD DATA(在for循环中并且可能使用seek命令)。
现在我正在尝试使用IGNORE LINES跳过已处理的记录,但如果有一个选项可以忽略来自BELOW的行,我不熟悉吗?
是否有更有效的方法来解析并将此类文件加载到DB中?
修改
我已经读过JDBC从5.1.3开始支持到LOAD DATA
的输入流,我可以用它来用输入流迭代文件并每次更改LOAD DATA
语句吗?
答案 0 :(得分:1)
我将我的代码作为解决方案附加,
此解决方案基于MySQL Connector / J 5.1.3及更高版本添加的additional functionality(setLocalInfileInputStream
)。
我将输入流管道插入LOAD DATA INTO
语句,而不是使用直接文件URL。
其他信息:我使用BoneCP作为连接池
public final void readFile(final String path)
throws IOException, SQLException, InterruptedException {
File file = new File(path);
final Connection connection = getSqlDataSource().getConnection();
Statement statement = SqlDataSource.getInternalStatement(connection.createStatement());
try{
Scanner fileScanner = new Scanner(file);
fileScanner.useDelimiter(Pattern.compile("^$", Pattern.MULTILINE));
while(fileScanner.hasNext()){
String line;
while ((line = fileScanner.nextLine()).isEmpty());
InputStream is = new ByteArrayInputStream(fileScanner.next().getBytes("UTF-8"));
String [] tableName = line.split(getSeparator());
setTable((tableName[0]+"_"+tableName[1]).replace('-', '_'));
String sql = "LOAD DATA LOCAL INFILE '" + SingleCsvImportBean.getOsDependantFileName(file) + "' "
+ "INTO TABLE " + SqlUtils.escape(getTable())
+ "FIELDS TERMINATED BY '" + getSeparator()
+ "' ESCAPED BY '' LINES TERMINATED BY '" + getLinefeed() + "' ";
sql += "(" + implodeStringArray(getFields(), ", ") + ")";
sql += getSetClause();
((com.mysql.jdbc.Statement) statement).setLocalInfileInputStream(is);
statement.execute(sql);
}
}finally{
statement.close();
connection.close();
}
}