【java/jdbc/二进制文件】将雇员表信息写入二进制文件 及 将二进制文件的雇员信息读取出来插进同构的另一张雇员表
【从CSV转向二进制文件的原因】
1.csv文件的分隔符逗号,可能出现在用户所选的字段中,分段失误后会导致信息丢失。
2.CSV文件信息容易被人读取,二进制文件则相对安全些。
【源表、数据及目的表】
create table emp( id number(12), name nvarchar2(10), age number(3), primary key(id) ); insert into emp select rownum, dbms_random.string('*',dbms_random.value(10,10)), dbms_random.value(18,60) from dual connect by level<21; create table emp_to( id number(12), name nvarchar2(10), age number(3), primary key(id) );
程序将从emp表读取数据写二进制文件,然后读取二进制文件写入目标表emp_to。
【读表写二进制文件程序】
package com.hy.datamasking; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.sql.*; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 读取emp表,将数据写入二进制文件 */ class Db2Binfile { //-- 以下为连接Oracle数据库的四大参数 private static final String DRIVER = "oracle.jdbc.driver.OracleDriver"; private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; private static final String USER = "luna"; private static final String PSWD = "1234"; public void export(String filename,String table,String[] fields){ String fieldLine=String.join(",",fields); Connection conn = null; Statement stmt = null; List<Map<String,String>> lines=new ArrayList<>(); try{ Class.forName(DRIVER); conn = DriverManager.getConnection(URL, USER, PSWD); String sql=String.format("select %s from %s order by 1",fieldLine,table); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { Map<String,String> map=new LinkedHashMap<>(); for(String field:fields){ String value = rs.getString(field); map.put(field,value); } lines.add(map); } rs.close(); } catch (Exception e) { e.printStackTrace(); } finally { try { stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } write2File(filename,lines); } private void write2File(String filename,List<Map<String,String>> lines){ try { DataOutputStream out = new DataOutputStream(new FileOutputStream(filename)); out.writeInt(lines.size()); for (Map<String,String> map:lines) { int fieldCnt=map.size(); out.writeInt(fieldCnt); for(Map.Entry<String,String> entry:map.entrySet()){ String key=entry.getKey(); int n=key.length(); out.writeInt(n); writeString(key,n,out); String value=entry.getValue(); n=value.length(); out.writeInt(n); writeString(value,n,out); } } }catch(Exception ex){ ex.printStackTrace(); } } // 写入最大长度为size的字符串,不足写0 private static void writeString(String str,int size,DataOutputStream out) throws Exception{ for(int i=0;i<size;i++){ char c=0; if(i<str.length()){ c=str.charAt(i); } out.writeChar(c); } } public static void main(String[] args){ Db2Binfile exp=new Db2Binfile(); exp.export("c:\\temp\\emp220310.dat","emp",new String[]{"id","name","age"}); } }
【读二进制文件写表的程序】
package com.hy.datamasking; import java.io.DataInput; import java.io.RandomAccessFile; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class Binfile2Db { //-- 以下为连接Oracle数据库的四大参数 private static final String DRIVER = "oracle.jdbc.driver.OracleDriver"; private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; private static final String USER = "luna"; private static final String PSWD = "1234"; public List<Map<String,String>> read(String filename){ List<Map<String,String>> lines=new ArrayList<>(); try { RandomAccessFile in = new RandomAccessFile(filename, "r"); int count=in.readInt(); for(int i=0;i<count;i++){ int fieldCnt=in.readInt(); Map<String,String> map=new LinkedHashMap<>(); for(int j=0;j<fieldCnt;j++){ int n=in.readInt(); String key=readString(n,in); n=in.readInt(); String value=readString(n,in); map.put(key,value); //String msg=String.format("%s:%s,",key,value); //System.out.print(msg); } lines.add(map); //System.out.println(); } }catch(Exception ex){ ex.printStackTrace(); } return lines; } // 读入最大长度为size的字符串 private static String readString(int size, DataInput in) throws Exception{ StringBuilder sb=new StringBuilder(); for(int i=0;i<size;i++){ char c=in.readChar(); if(c==0){ continue; }else{ sb.append(c); } } return sb.toString(); } public void insert(String tablename,List<Map<String,String>> lines){ Connection conn = null; Statement stmt = null; try{ Class.forName(DRIVER); conn = DriverManager.getConnection(URL, USER, PSWD); stmt = conn.createStatement(); for (Map<String,String> map:lines) { List<String> keys=new ArrayList<>(); List<String> values=new ArrayList<>(); for(Map.Entry<String,String> entry:map.entrySet()){ String key=entry.getKey(); keys.add(key); String value=entry.getValue(); values.add("'"+value+"'"); } String sql=String.format("insert into %s(%s) values(%s)",tablename,String.join(",",keys),String.join(",",values)); stmt.execute(sql); } } catch (Exception e) { e.printStackTrace(); } finally { try { stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args){ Binfile2Db imp=new Binfile2Db(); List<Map<String,String>> lines=imp.read("c:\\temp\\emp220310.dat"); imp.insert("emp_to",lines); } }
【最后emp_to表的数据】
SQL> select * from emp_to; ID NAME AGE ---------- -------------------- ---------- 1 EYUVOYRXUI 21 2 SKCTTMGJEG 21 3 QDTQKDAAKQ 55 4 UXOBXKCXWG 19 5 TFPNXOJVBO 37 6 BSYEZYNNIR 52 7 XIGBNCCJJI 25 8 RKVMFJXVQM 27 9 JPKEXVOQOV 41 10 RMELXQHSCU 45 11 HKJYEANGYQ 28 ID NAME AGE ---------- -------------------- ---------- 12 YRAYESTIXA 57 13 ZEOSGWBRZT 24 14 WCWNMUVPEF 35 15 IBBZUOHHPX 47 16 XOXYKJLUUX 38 17 NOXBGIEIGP 48 18 LIYORVMTRU 37 19 EHJYCWSVQY 20 20 XLPVNKMIXW 39
【精髓点评】
写二进制文件的关键在于在每个字符串前面写有其长度。这样做以后,读取时先用readInt读取长度,再以此长度读取字符串就毫不费力了。
另一个技巧是把字段名和字段值写在一起,这样组合插入语句就很方便了。
原先设想还要取字段的metadata,现在看当时是多虑了。
有趣的编程有着莫大的创造式快乐,这是我工作的最大动力。
END
分类:
Java.JDBC
, Java.二进制文件操作
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2020-03-10 【Canvas与化学】硅元素
2020-03-10 Oracle中select子句取值先于order by子句执行而导致rownum伪列未按预期取值导致的问题
2020-03-10 【Canvas与艺术】蓝波纹白底黄星徽章
2019-03-10 [JS]两个常用的取随机整数的函数
2019-03-10 【Canvas与艺术】十角大楼