0

在一家 IT 公司实习时,我被分配了一项任务,即编写脚本或 java 程序将 CSV 文件转换为 LDIF 文件格式,我相信许多组织都使用这种格式来填充/修改/删除他们的许多用户目录. 我正在尝试编写一个 java 程序来帮助我将 CSV 文件转换为 LDIF 文件。然后将此 LDIF 文件导入电子目录以添加新用户。目前,我有一个简单的程序可以运行,但需要我无法提供的重大改进。


CSV 文件示例截图(第一行是标题):
csv 文件示例
Notepad++ 中的示例 CSV 文件:Notepad++中的
csv 文件
(第一行是标题。一行中的每个元素用逗号 (,) 分隔)

示例 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


注意:作为标题的第一行从输出中排除。CSV 文件中的每一行都转换为一组数据(lines=dn: 到 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,但我无法找到解决问题的方法。

任何形式的帮助将不胜感激。抱歉,如果可能有很多错误,这是我第一次在这里提问。因此,任何形式的反馈也会有很大帮助。谢谢!

4

2 回答 2

1

像这样的东西应该跳过空列:

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"
            );
于 2015-10-30T10:39:23.450 回答
1

我打算对先前/接受的答案发表评论,但我没有能够发表评论的声誉。相反,我会添加一个不回答的回复,希望能帮助将来看到这个问题的任何人......

在处理可能出现的任何可能数据时,所提供的解决方案似乎不完整。如果您查看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.

如果您想要更完整的解决方案,应更新已接受的解决方案以正确处理编码。

于 2017-08-10T19:27:49.727 回答