使用 java 将 CSV 文件转换为 LDIF 文件
Conversion of CSV file to LDIF file using java
我在一家 IT 公司实习时,分配给我的任务是编写脚本或 java 程序,将 CSV 文件转换为 LDIF 文件格式,我相信很多组织都使用这种格式 populate/modify/delete他们的目录很多用户。我正在尝试编写一个 java 程序来帮助我将 CSV 文件转换为 LDIF 文件。然后将此 LDIF 文件导入 e-directory 以添加新用户。目前,我有一个简单的程序可以工作,但需要我无法提供的重大改进。
示例 CSV 文件的屏幕截图(第一行是 header):
csv file sample
Notepad++ 中的示例 CSV 文件:
csv file in Notepad++
(第一行是header。一行中的每个元素用逗号(,)分隔)
使用下面给出的示例代码生成的示例 LDIF 文件(输出):
dn: cn=demotest1, ou=Data, o=Data
changetype: add
ou: Data
objectClass: dt1
objectClass: test_demo1
objectClass: demotest1
objectClass: Employee
cn: demotest1
uid: test_demo1
SAMAccountName: demt1
givenName: demotest1
sn: dt1
dn: cn=demotest2, ou=Data, o=Data
changetype: add
ou: Data
objectClass: dt2
objectClass: test_demo2
objectClass: demotest2
objectClass: Employee
cn: demotest2
uid: test_demo2
SAMAccountName: demt2
givenName: demotest2
sn: dt2
注意:作为 header 的第一行已从输出中排除。 CSV文件中的每一行被转换成一组数据(lines= dn: to sn:)并且每组数据之间用空行分隔。
下面是我用来生成上述 LDIF 文件的代码示例:
package readcsv;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/**
*
* @author Dorjee
*/
public class ReadCSV {
public static void main(String[] args) {
ReadCSV obj = new ReadCSV();
obj.run();
}
public void run() {
String csvFile = "/Users/Dorjee/Desktop/sampleCSV.csv"; //Path of file to be read.
BufferedReader br = null;
String line = "";
String csvSplitBy = ",";
String[] column;
int count = 0;
try {
PrintStream out = new PrintStream(new FileOutputStream("OutputLDIFFile.ldif"));
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// using comma as separator
column = line.split(csvSplitBy);
//End format of the ouput file.
//Change according to .CSV file.
//Count used to exclude the reading of the first line.
if (count > 0) {
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ "\nou: " + column[7]
+ "\nobjectClass: " + column[3]
+ "\nobjectClass: " + column[4]
+ "\nobjectClass: " + column[5]
+ "\nobjectClass: " + column[6]
+ "\ncn: " + column[5]
+ "\nuid: "+column[4]
+ "\nSAMAccountName: "+column[1]
+ "\ngivenName: "+column[0]
+ "\nsn: "+column[3]
+ "\n"
);
}
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Done");
}
}
这是一个简单的代码,可帮助从 CSV 文件生成 LDIF 文件。这很有用,因为要在此处生成的数据集可能跨越数千行。但是这段代码显然是不够的。如您所见,每次需要将具有不同列数的不同 CSV 文件转换为 LDIF 文件时,我都必须更改上面突出显示区域的代码。这会占用大量时间,因为我遇到过超过 50 列的文件,并且在我手动更改代码时增加了出错的机会。最重要的是,某些列具有空值(需要从输出中排除)。
• 如何排除输出中的空值?
• 即使CSV 文件的列数不同,是否有办法自动生成输出?我试过 ArrayList 但我想不出解决问题的方法。
任何形式的帮助将不胜感激。抱歉,如果可能有很多错误,这是我第一次在这里提问。所以任何类型的反馈也会有很大帮助。谢谢!
类似这样的内容应该跳过空列:
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ ((column[7].length()>0)?"\nou: " + column[7]:"")
+ ((column[3].length()>0)?"\nobjectClass: " + column[3]:"")
+ ((column[4].length()>0)?"\nobjectClass: " + column[4]:"")
+ ((column[5].length()>0)?"\nobjectClass: " + column[5]:"")
+ ((column[6].length()>0)?"\nobjectClass: " + column[6]:"")
+ ((column[5].length()>0)?"\ncn: " + column[5]:"")
+ ((column[4].length()>0)?"\nuid: "+column[4]:"")
+ ((column[1].length()>0)?"\nSAMAccountName: "+column[1]:"")
+ ((column[0].length()>0)?"\ngivenName: "+column[0]:"")
+ ((column[3].length()>0)?"\nsn: "+column[3]:"")
+ "\n"
);
如果您还需要检查列数:
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ ((column.length > 7 && column[7].length()>0)?"\nou: " + column[7]:"")
+ ((column.length > 3 && column[3].length()>0)?"\nobjectClass: " + column[3]:"")
+ ((column.length > 4 && column[4].length()>0)?"\nobjectClass: " + column[4]:"")
+ ((column.length > 5 && column[5].length()>0)?"\nobjectClass: " + column[5]:"")
+ ((column.length > 6 && column[6].length()>0)?"\nobjectClass: " + column[6]:"")
+ ((column.length > 5 && column[5].length()>0)?"\ncn: " + column[5]:"")
+ ((column.length > 4 && column[4].length()>0)?"\nuid: "+column[4]:"")
+ ((column.length > 1 && column[1].length()>0)?"\nSAMAccountName: "+column[1]:"")
+ ((column.length > 0 && column[0].length()>0)?"\ngivenName: "+column[0]:"")
+ ((column.length > 3 && column[3].length()>0)?"\nsn: "+column[3]:"")
+ "\n"
);
它看起来有点难看,使用辅助函数可能会更容易。
static public String check(String column[],String line,int index) {
return ((column.length > index && column[index].length()>0)?line + column[index]:"");
}
...
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ check(column,"\nou: ",7)
+ check(column,"\nobjectClass: " ,3)
+ check(column,"\nobjectClass: ",4)
+ check(column,"\nobjectClass: ",5)
+ check(column,"\nobjectClass: ",6)
+ check(column,"\ncn: ",5)
+ check(column,"\nuid: ",4)
+ check(column,"\nSAMAccountName: ",1)
+ check(column,"\ngivenName: ",0)
+ check(column,"\nsn: ",3)
+ "\n"
);
我本来打算对 previous/accepted 的回答发表评论,但我没有资格发表评论。相反,我会添加一个无答案的回复,希望能帮助将来看到这个的任何人...
在处理可能出现的任何可能数据时,所提供的解决方案似乎并不完整。如果您查看 RFC2849,您会发现类似的建议(均在第 5 页):
4) ... Any
value that contains characters other than those defined as
"SAFE-CHAR", or begins with a character other than those
defined as "SAFE-INIT-CHAR", above, MUST be base-64 encoded.
Other values MAY be base-64 encoded.
其中 SAFE-INIT-CHAR 定义为
SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
%x21-39 / %x3B / %x3D-7F
; any value <= 127 except NUL, LF, CR,
; SPACE, colon (":", ASCII 58 decimal)
; and less-than ("<" , ASCII 60 decimal)
和
8) Values or distinguished names that end with SPACE SHOULD be
base-64 encoded.
如果您想要更完整的解决方案,应更新已接受的解决方案以正确处理编码。
我在一家 IT 公司实习时,分配给我的任务是编写脚本或 java 程序,将 CSV 文件转换为 LDIF 文件格式,我相信很多组织都使用这种格式 populate/modify/delete他们的目录很多用户。我正在尝试编写一个 java 程序来帮助我将 CSV 文件转换为 LDIF 文件。然后将此 LDIF 文件导入 e-directory 以添加新用户。目前,我有一个简单的程序可以工作,但需要我无法提供的重大改进。
示例 CSV 文件的屏幕截图(第一行是 header):
csv file sample
Notepad++ 中的示例 CSV 文件:
csv file in Notepad++
(第一行是header。一行中的每个元素用逗号(,)分隔)
使用下面给出的示例代码生成的示例 LDIF 文件(输出):
dn: cn=demotest1, ou=Data, o=Data
changetype: add
ou: Data
objectClass: dt1
objectClass: test_demo1
objectClass: demotest1
objectClass: Employee
cn: demotest1
uid: test_demo1
SAMAccountName: demt1
givenName: demotest1
sn: dt1
dn: cn=demotest2, ou=Data, o=Data
changetype: add
ou: Data
objectClass: dt2
objectClass: test_demo2
objectClass: demotest2
objectClass: Employee
cn: demotest2
uid: test_demo2
SAMAccountName: demt2
givenName: demotest2
sn: dt2
注意:作为 header 的第一行已从输出中排除。 CSV文件中的每一行被转换成一组数据(lines= dn: to sn:)并且每组数据之间用空行分隔。
下面是我用来生成上述 LDIF 文件的代码示例:
package readcsv;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/**
*
* @author Dorjee
*/
public class ReadCSV {
public static void main(String[] args) {
ReadCSV obj = new ReadCSV();
obj.run();
}
public void run() {
String csvFile = "/Users/Dorjee/Desktop/sampleCSV.csv"; //Path of file to be read.
BufferedReader br = null;
String line = "";
String csvSplitBy = ",";
String[] column;
int count = 0;
try {
PrintStream out = new PrintStream(new FileOutputStream("OutputLDIFFile.ldif"));
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// using comma as separator
column = line.split(csvSplitBy);
//End format of the ouput file.
//Change according to .CSV file.
//Count used to exclude the reading of the first line.
if (count > 0) {
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ "\nou: " + column[7]
+ "\nobjectClass: " + column[3]
+ "\nobjectClass: " + column[4]
+ "\nobjectClass: " + column[5]
+ "\nobjectClass: " + column[6]
+ "\ncn: " + column[5]
+ "\nuid: "+column[4]
+ "\nSAMAccountName: "+column[1]
+ "\ngivenName: "+column[0]
+ "\nsn: "+column[3]
+ "\n"
);
}
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Done");
}
}
这是一个简单的代码,可帮助从 CSV 文件生成 LDIF 文件。这很有用,因为要在此处生成的数据集可能跨越数千行。但是这段代码显然是不够的。如您所见,每次需要将具有不同列数的不同 CSV 文件转换为 LDIF 文件时,我都必须更改上面突出显示区域的代码。这会占用大量时间,因为我遇到过超过 50 列的文件,并且在我手动更改代码时增加了出错的机会。最重要的是,某些列具有空值(需要从输出中排除)。
• 如何排除输出中的空值?
• 即使CSV 文件的列数不同,是否有办法自动生成输出?我试过 ArrayList 但我想不出解决问题的方法。
类似这样的内容应该跳过空列:
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ ((column[7].length()>0)?"\nou: " + column[7]:"")
+ ((column[3].length()>0)?"\nobjectClass: " + column[3]:"")
+ ((column[4].length()>0)?"\nobjectClass: " + column[4]:"")
+ ((column[5].length()>0)?"\nobjectClass: " + column[5]:"")
+ ((column[6].length()>0)?"\nobjectClass: " + column[6]:"")
+ ((column[5].length()>0)?"\ncn: " + column[5]:"")
+ ((column[4].length()>0)?"\nuid: "+column[4]:"")
+ ((column[1].length()>0)?"\nSAMAccountName: "+column[1]:"")
+ ((column[0].length()>0)?"\ngivenName: "+column[0]:"")
+ ((column[3].length()>0)?"\nsn: "+column[3]:"")
+ "\n"
);
如果您还需要检查列数:
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ ((column.length > 7 && column[7].length()>0)?"\nou: " + column[7]:"")
+ ((column.length > 3 && column[3].length()>0)?"\nobjectClass: " + column[3]:"")
+ ((column.length > 4 && column[4].length()>0)?"\nobjectClass: " + column[4]:"")
+ ((column.length > 5 && column[5].length()>0)?"\nobjectClass: " + column[5]:"")
+ ((column.length > 6 && column[6].length()>0)?"\nobjectClass: " + column[6]:"")
+ ((column.length > 5 && column[5].length()>0)?"\ncn: " + column[5]:"")
+ ((column.length > 4 && column[4].length()>0)?"\nuid: "+column[4]:"")
+ ((column.length > 1 && column[1].length()>0)?"\nSAMAccountName: "+column[1]:"")
+ ((column.length > 0 && column[0].length()>0)?"\ngivenName: "+column[0]:"")
+ ((column.length > 3 && column[3].length()>0)?"\nsn: "+column[3]:"")
+ "\n"
);
它看起来有点难看,使用辅助函数可能会更容易。
static public String check(String column[],String line,int index) {
return ((column.length > index && column[index].length()>0)?line + column[index]:"");
}
...
out.println("dn: cn="+column[5]+", ou="+column[7]+", o=Data"+
"\nchangetype: " + column[2]
+ check(column,"\nou: ",7)
+ check(column,"\nobjectClass: " ,3)
+ check(column,"\nobjectClass: ",4)
+ check(column,"\nobjectClass: ",5)
+ check(column,"\nobjectClass: ",6)
+ check(column,"\ncn: ",5)
+ check(column,"\nuid: ",4)
+ check(column,"\nSAMAccountName: ",1)
+ check(column,"\ngivenName: ",0)
+ check(column,"\nsn: ",3)
+ "\n"
);
我本来打算对 previous/accepted 的回答发表评论,但我没有资格发表评论。相反,我会添加一个无答案的回复,希望能帮助将来看到这个的任何人...
在处理可能出现的任何可能数据时,所提供的解决方案似乎并不完整。如果您查看 RFC2849,您会发现类似的建议(均在第 5 页):
4) ... Any value that contains characters other than those defined as "SAFE-CHAR", or begins with a character other than those defined as "SAFE-INIT-CHAR", above, MUST be base-64 encoded. Other values MAY be base-64 encoded.
其中 SAFE-INIT-CHAR 定义为
SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B / %x3D-7F ; any value <= 127 except NUL, LF, CR, ; SPACE, colon (":", ASCII 58 decimal) ; and less-than ("<" , ASCII 60 decimal)
和
8) Values or distinguished names that end with SPACE SHOULD be base-64 encoded.
如果您想要更完整的解决方案,应更新已接受的解决方案以正确处理编码。