CSV文件读取与生成以及Excel文件的读取生成

 

其一:CSV文件读取与生成

 ①CSV文件读取

     读取操作类:

Java代码   收藏代码
  1. public class CSVReader {  
  2.     private BufferedReader br;  
  3.   
  4.     private boolean hasNext = true;  
  5.   
  6.     private char separator;//分隔符  
  7.   
  8.     private char quotechar;//引号符  
  9.   
  10.     private int skipLines;//  
  11.   
  12.     private boolean linesSkiped; //转移线  
  13.   
  14.     /** The default separator to use if none is supplied to the constructor. */  
  15.     public static final char DEFAULT_SEPARATOR = ',';  
  16.   
  17.     /** 
  18.      * The default quote character to use if none is supplied to the 
  19.      * constructor. 
  20.      */  
  21.     public static final char DEFAULT_QUOTE_CHARACTER = '"';  
  22.   
  23.     /** 
  24.      * The default line to start reading. 
  25.      */  
  26.     public static final int DEFAULT_SKIP_LINES = 0;  
  27.   
  28.     /** 
  29.      * Constructs CSVReader using a comma for the separator. 
  30.      *  
  31.      * @param reader 
  32.      *            the reader to an underlying CSV source. 
  33.      */  
  34.     public CSVReader(Reader reader) {  
  35.         this(reader, DEFAULT_SEPARATOR);  
  36.     }  
  37.   
  38.     /** 
  39.      * Constructs CSVReader with supplied separator. 
  40.      *  
  41.      * @param reader 
  42.      *            the reader to an underlying CSV source. 
  43.      * @param separator 
  44.      *            the delimiter to use for separating entries. 
  45.      */  
  46.     public CSVReader(Reader reader, char separator) {  
  47.         this(reader, separator, DEFAULT_QUOTE_CHARACTER);  
  48.     }  
  49.   
  50.     /** 
  51.      * Constructs CSVReader with supplied separator and quote char. 
  52.      *  
  53.      * @param reader 
  54.      *            the reader to an underlying CSV source. 
  55.      * @param separator 
  56.      *            the delimiter to use for separating entries 
  57.      * @param quotechar 
  58.      *            the character to use for quoted elements 
  59.      */  
  60.     public CSVReader(Reader reader, char separator, char quotechar) {  
  61.         this(reader, separator, quotechar, DEFAULT_SKIP_LINES);  
  62.     }  
  63.   
  64.     /** 
  65.      * Constructs CSVReader with supplied separator and quote char. 
  66.      *  
  67.      * @param reader 
  68.      *            the reader to an underlying CSV source. 
  69.      * @param separator 
  70.      *            the delimiter to use for separating entries 
  71.      * @param quotechar 
  72.      *            the character to use for quoted elements 
  73.      * @param line 
  74.      *            the line number to skip for start reading 
  75.      */  
  76.     public CSVReader(Reader reader, char separator, char quotechar, int line) {  
  77.         this.br = new BufferedReader(reader);  
  78.         this.separator = separator;  
  79.         this.quotechar = quotechar;  
  80.         this.skipLines = line;  
  81.     }  
  82.   
  83.     /** 
  84.      * Reads the entire file into a List with each element being a String[] of 
  85.      * tokens. 
  86.      *  
  87.      * @return a List of String[], with each String[] representing a line of the 
  88.      *         file. 
  89.      *  
  90.      * @throws IOException 
  91.      *             if bad things happen during the read 
  92.      */  
  93.     public List readAll() throws IOException {  
  94.   
  95.         List allElements = new ArrayList();  
  96.         while (hasNext) {  
  97.             String[] nextLineAsTokens = readNext();  
  98.             if (nextLineAsTokens != null)  
  99.                 allElements.add(nextLineAsTokens);  
  100.         }  
  101.         return allElements;  
  102.   
  103.     }  
  104.   
  105.     /** 
  106.      * Reads the next line from the buffer and converts to a string array. 
  107.      *  
  108.      * @return a string array with each comma-separated element as a separate 
  109.      *         entry. 
  110.      *  
  111.      * @throws IOException 
  112.      *             if bad things happen during the read 
  113.      */  
  114.     public String[] readNext() throws IOException {  
  115.   
  116.         String nextLine = getNextLine();  
  117.         return hasNext ? parseLine(nextLine) : null;  
  118.     }  
  119.   
  120.     /** 
  121.      * Reads the next line from the file. 
  122.      *  
  123.      * @return the next line from the file without trailing newline 
  124.      * @throws IOException 
  125.      *             if bad things happen during the read 
  126.      */  
  127.     private String getNextLine() throws IOException {  
  128.         if (!this.linesSkiped) {  
  129.             for (int i = 0; i < skipLines; i++) {  
  130.                 br.readLine();  
  131.             }  
  132.             this.linesSkiped = true;  
  133.         }  
  134.         String nextLine = br.readLine();  
  135.         if (nextLine == null) {  
  136.             hasNext = false;  
  137.         }  
  138.         return hasNext ? nextLine : null;  
  139.     }  
  140.   
  141.     /** 
  142.      * Parses an incoming String and returns an array of elements. 
  143.      *  
  144.      * @param nextLine 
  145.      *            the string to parse 
  146.      * @return the comma-tokenized list of elements, or null if nextLine is null 
  147.      * @throws IOException 
  148.      *             if bad things happen during the read 
  149.      */  
  150.     private String[] parseLine(String nextLine) throws IOException {  
  151.   
  152.         if (nextLine == null) {  
  153.             return null;  
  154.         }  
  155.   
  156.         List tokensOnThisLine = new ArrayList();  
  157.         StringBuffer sb = new StringBuffer();  
  158.         boolean inQuotes = false;  
  159.         do {  
  160.             if (inQuotes) {  
  161.                 // continuing a quoted section, reappend newline  
  162.                 sb.append("\n");  
  163.                 nextLine = getNextLine();  
  164.                 if (nextLine == null)  
  165.                     break;  
  166.             }  
  167.             for (int i = 0; i < nextLine.length(); i++) {  
  168.   
  169.                 char c = nextLine.charAt(i);  
  170.                 if (c == quotechar) {  
  171.                     // this gets complex... the quote may end a quoted block, or  
  172.                     // escape another quote.  
  173.                     // do a 1-char lookahead:  
  174.                     if (inQuotes // we are in quotes, therefore there can be  
  175.                             // escaped quotes in here.  
  176.                             && nextLine.length() > (i + 1// there is indeed  
  177.                             // another character  
  178.                             // to check.  
  179.                             && nextLine.charAt(i + 1) == quotechar) { // ..and  
  180.                         // that  
  181.                         // char.  
  182.                         // is a  
  183.                         // quote  
  184.                         // also.  
  185.                         // we have two quote chars in a row == one quote char,  
  186.                         // so consume them both and  
  187.                         // put one on the token. we do *not* exit the quoted  
  188.                         // text.  
  189.                         sb.append(nextLine.charAt(i + 1));  
  190.                         i++;  
  191.                     } else {  
  192.                         inQuotes = !inQuotes;  
  193.                         // the tricky case of an embedded quote in the middle:  
  194.                         // a,bc"d"ef,g  
  195.                         if (i > 2 // not on the begining of the line  
  196.                                 && nextLine.charAt(i - 1) != this.separator // not  
  197.                                 // at  
  198.                                 // the  
  199.                                 // begining  
  200.                                 // of  
  201.                                 // an  
  202.                                 // escape  
  203.                                 // sequence  
  204.                                 && nextLine.length() > (i + 1)  
  205.                                 && nextLine.charAt(i + 1) != this.separator // not  
  206.                         // at  
  207.                         // the  
  208.                         // end  
  209.                         // of  
  210.                         // an  
  211.                         // escape  
  212.                         // sequence  
  213.                         ) {  
  214.                             sb.append(c);  
  215.                         }  
  216.                     }  
  217.                 } else if (c == separator && !inQuotes) {  
  218.                     tokensOnThisLine.add(sb.toString());  
  219.                     sb = new StringBuffer(); // start work on next token  
  220.                 } else {  
  221.                     sb.append(c);  
  222.                 }  
  223.             }  
  224.         } while (inQuotes);  
  225.         tokensOnThisLine.add(sb.toString());  
  226.         return (String[]) tokensOnThisLine.toArray(new String[0]);  
  227.   
  228.     }  
  229.   
  230.     /** 
  231.      * Closes the underlying reader. 
  232.      *  
  233.      * @throws IOException 
  234.      *             if the close fails 
  235.      */  
  236.     public void close() throws IOException {  
  237.         br.close();  
  238.     }  
  239.   
  240. }

    读取测试类

  


Java代码   收藏代码
  1. public class CSVReaderTest {    
  2.     CSVReader csvr;  
  3.   
  4.     /** 
  5.      * Setup the test. 
  6.      */  
  7.     @Before  
  8.     public void init() throws Exception {  
  9.         StringBuffer sb = new StringBuffer();  
  10.         sb.append("a,b,c").append("\n"); // standard case  
  11.         sb.append("a,\"b,b,b\",c").append("\n"); // quoted elements  
  12.         sb.append(",,").append("\n"); // empty elements  
  13.         sb.append("a,\"PO Box 123,\nKippax,ACT. 2615.\nAustralia\",d.\n");//Glen \"The Man\" Smith  
  14.         sb.append("\"Glen \"\"The Man\"\" Smith\",Athlete,Developer\n"); // Test  
  15.         // quoted  
  16.         // quote  
  17.         // chars  
  18.         sb.append("\"\"\"\"\"\",\"test\"\n"); // """""","test" representing: "",  
  19.         // test  
  20.         sb.append("\"a\nb\",b,\"\nd\",e\n");  
  21.         csvr = new CSVReader(new FileReader("d:/myfile.csv"));//这种方式就是读取文件了  
  22.           
  23.         //csvr = new CSVReader(new StringReader(sb.toString()));//这种方式就是读取字符串了  
  24.     }  
  25.     //测试读取文件  
  26.     @Test  
  27.     public void test1() throws IOException{  
  28.           
  29.         CSVReader c = new CSVReader(new FileReader("d:/myfile.csv"), ',',  
  30.                 '\"'1);  
  31.         String[] nextline=c.readNext();  
  32.         System.out.println(nextline[0]);  
  33.         assertEquals("CRM4005", nextline[0]);  
  34.     }  
  35.   
  36.     /** 
  37.      * Tests iterating over a reader. 
  38.      *  
  39.      * @throws IOException 
  40.      *             if the reader fails. 
  41.      */  
  42.       
  43.     public void ParseLine() throws IOException {  
  44.   
  45.         // test normal case //测试普通示例  
  46.         String[] nextLine = csvr.readNext(); //第一行  
  47.         assertEquals("a", nextLine[0]); //第一行第一个元素  
  48.         assertEquals("b", nextLine[1]); //第一行第二个元素  
  49.         assertEquals("c", nextLine[2]); //第一行第三个元素  
  50.   
  51.         // test quoted commas 测试引用起来的逗号   
  52.         nextLine = csvr.readNext();  
  53.         assertEquals("a", nextLine[0]);  
  54.         assertEquals("b,b,b", nextLine[1]);  
  55.         assertEquals("c", nextLine[2]);  
  56.   
  57.         // test empty elements 测试空元素   
  58.         nextLine = csvr.readNext();  
  59.         assertEquals(3, nextLine.length);  
  60.   
  61.         // test multiline quoted //测试多行引用的  
  62.         nextLine = csvr.readNext();  
  63.         assertEquals(3, nextLine.length);  
  64.   
  65.         // test quoted quote chars //测试引用起来的引号字符  
  66.         nextLine = csvr.readNext();  
  67.         assertEquals("Glen \"The Man\" Smith", nextLine[0]);  
  68.   
  69.         nextLine = csvr.readNext();  
  70.         assertTrue(nextLine[0].equals("\"\"")); // check the tricky situation //检查复杂的位置  
  71.         assertTrue(nextLine[1].equals("test")); // make sure we didn't ruin the   
  72.         // next field.. 确保不破坏下一个域  
  73.   
  74.         nextLine = csvr.readNext();  
  75.         assertEquals(4, nextLine.length);  
  76.   
  77.         // test end of stream 测试流的结尾  
  78.         assertEquals(null, csvr.readNext());  
  79.   
  80.     }  
  81.   
  82.     /** 
  83.      * Test parsing to a list. 
  84.      *  
  85.      * @throws IOException 
  86.      *             if the reader fails. 
  87.      */  
  88.     @SuppressWarnings("unchecked")  
  89.       
  90.     public void testParseAll() throws IOException {  
  91.   
  92.         List allElements = csvr.readAll();  
  93.         assertEquals(7, allElements.size());//应该指的是总共有多少行  
  94.   
  95.     }  
  96.   
  97.     /** 
  98.      * Tests constructors with optional delimiters and optional quote char. 
  99.      *  
  100.      * @throws IOException 
  101.      *             if the reader fails. 
  102.      */  
  103.       
  104.     public void testOptionalConstructors() throws IOException {  
  105.   
  106.         StringBuffer sb = new StringBuffer();  
  107.         sb.append("a\tb\tc").append("\n"); // tab separated case  
  108.         sb.append("a\t'b\tb\tb'\tc").append("\n"); // single quoted elements  
  109.         CSVReader c = new CSVReader(new StringReader(sb.toString()), '\t''\'');  
  110.         //上面的制定了分隔符为\t,指定了引号为单引号  
  111.         String[] nextLine = c.readNext();  
  112.         assertEquals(3, nextLine.length);  
  113.   
  114.         nextLine = c.readNext();  
  115.         assertEquals(3, nextLine.length);  
  116.   
  117.     }  
  118.   
  119.     /** 
  120.      * Tests option to skip the first few lines of a file. 
  121.      *  
  122.      * @throws IOException 
  123.      *             if bad things happen 
  124.      */  
  125.       
  126.     public void testSkippingLines() throws IOException {  
  127.   
  128.         StringBuffer sb = new StringBuffer();  
  129.         sb.append("Skip this line\t with tab").append("\n"); // should skip this  
  130.         sb.append("And this line too").append("\n"); // and this  
  131.         sb.append("a\t'b\tb\tb'\tc").append("\n"); // single quoted elements  
  132.         CSVReader c = new CSVReader(new StringReader(sb.toString()), '\t',  
  133.                 '\''2);//跳过两行来读取文本,那么读取的当然是第三行了  
  134.   
  135.         String[] nextLine = c.readNext();  
  136.         assertEquals(3, nextLine.length);  
  137.   
  138.         assertEquals("a", nextLine[0]);  
  139.     }  
  140.   
  141.     /** 
  142.      * Tests quotes in the middle of an element. 
  143.      *  
  144.      * @throws IOException 
  145.      *             if bad things happen 
  146.      */  
  147.       
  148.     public void testParsedLineWithInternalQuota() throws IOException {  
  149.   
  150.         StringBuffer sb = new StringBuffer();  
  151.   
  152.         sb.append("a,123\"4\"567,c").append("\n");// a,123"4",c  
  153.   
  154.         CSVReader c = new CSVReader(new StringReader(sb.toString()));  
  155.   
  156.         String[] nextLine = c.readNext();  
  157.         assertEquals(3, nextLine.length);  
  158.   
  159.         System.out.println(nextLine[1]);  
  160.         assertEquals("123\"4\"567", nextLine[1]);  
  161.   
  162.     }  
  163.   
  164.     /** 
  165.      * The Test Runner for commandline use. 
  166.      *  
  167.      * @param args 
  168.      *            no args required 
  169.      */  
  170.     public static void main(String args[]) {  
  171.         junit.textui.TestRunner.run(CSVReaderTest.class);//这个主要是用来测试继承自TestCase类的所有方法,并且方法名称那个以test开头,在此我没有继承所以这里报错正常  
  172.     }  
  173.   
  174. }  

 

 ②CSV文件写入

    文件写入操作类

    

Java代码   收藏代码
  1. public class CSVWriter {  
  2.     private Writer rawWriter;  
  3.   
  4.     private PrintWriter pw;  
  5.   
  6.     private char separator;  
  7.   
  8.     private char quotechar;  
  9.   
  10.     private char escapechar;  
  11.   
  12.     private String lineEnd;  
  13.   
  14.     /** The character used for escaping quotes. */  
  15.     public static final char DEFAULT_ESCAPE_CHARACTER = '"';  
  16.   
  17.     /** The default separator to use if none is supplied to the constructor. */  
  18.     public static final char DEFAULT_SEPARATOR = ',';  
  19.   
  20.     /** 
  21.      * The default quote character to use if none is supplied to the 
  22.      * constructor. 
  23.      */  
  24.     public static final char DEFAULT_QUOTE_CHARACTER = '"';  
  25.   
  26.     /** The quote constant to use when you wish to suppress all quoting. */  
  27.     public static final char NO_QUOTE_CHARACTER = '\u0000';  
  28.   
  29.     /** The escape constant to use when you wish to suppress all escaping. */  
  30.     public static final char NO_ESCAPE_CHARACTER = '\u0000';  
  31.   
  32.     /** Default line terminator uses platform encoding. */  
  33.     public static final String DEFAULT_LINE_END = "\n";  
  34.   
  35.     private static final SimpleDateFormat TIMESTAMP_FORMATTER = new SimpleDateFormat(  
  36.             "dd-MMM-yyyy HH:mm:ss");  
  37.   
  38.     private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(  
  39.             "dd-MMM-yyyy");  
  40.   
  41.     /** 
  42.      * Constructs CSVWriter using a comma for the separator. 
  43.      *  
  44.      * @param writer 
  45.      *            the writer to an underlying CSV source. 
  46.      */  
  47.     public CSVWriter(Writer writer) {  
  48.         this(writer, DEFAULT_SEPARATOR);  
  49.     }  
  50.   
  51.     /** 
  52.      * Constructs CSVWriter with supplied separator. 
  53.      *  
  54.      * @param writer 
  55.      *            the writer to an underlying CSV source. 
  56.      * @param separator 
  57.      *            the delimiter to use for separating entries. 
  58.      */  
  59.     public CSVWriter(Writer writer, char separator) {  
  60.         this(writer, separator, DEFAULT_QUOTE_CHARACTER);  
  61.     }  
  62.   
  63.     /** 
  64.      * Constructs CSVWriter with supplied separator and quote char. 
  65.      *  
  66.      * @param writer 
  67.      *            the writer to an underlying CSV source. 
  68.      * @param separator 
  69.      *            the delimiter to use for separating entries 
  70.      * @param quotechar 
  71.      *            the character to use for quoted elements 
  72.      */  
  73.     public CSVWriter(Writer writer, char separator, char quotechar) {  
  74.         this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER);  
  75.     }  
  76.   
  77.     /** 
  78.      * Constructs CSVWriter with supplied separator and quote char. 
  79.      *  
  80.      * @param writer 
  81.      *            the writer to an underlying CSV source. 
  82.      * @param separator 
  83.      *            the delimiter to use for separating entries 
  84.      * @param quotechar 
  85.      *            the character to use for quoted elements 
  86.      * @param escapechar 
  87.      *            the character to use for escaping quotechars or escapechars 
  88.      */  
  89.     public CSVWriter(Writer writer, char separator, char quotechar,  
  90.             char escapechar) {  
  91.         this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END);  
  92.     }  
  93.   
  94.     /** 
  95.      * Constructs CSVWriter with supplied separator and quote char. 
  96.      *  
  97.      * @param writer 
  98.      *            the writer to an underlying CSV source. 
  99.      * @param separator 
  100.      *            the delimiter to use for separating entries 
  101.      * @param quotechar 
  102.      *            the character to use for quoted elements 
  103.      * @param lineEnd 
  104.      *            the line feed terminator to use 
  105.      */  
  106.     public CSVWriter(Writer writer, char separator, char quotechar,  
  107.             String lineEnd) {  
  108.         this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);  
  109.     }  
  110.   
  111.     /** 
  112.      * Constructs CSVWriter with supplied separator, quote char, escape char and 
  113.      * line ending. 
  114.      *  
  115.      * @param writer 
  116.      *            the writer to an underlying CSV source. 
  117.      * @param separator 
  118.      *            the delimiter to use for separating entries 
  119.      * @param quotechar 
  120.      *            the character to use for quoted elements 
  121.      * @param escapechar 
  122.      *            the character to use for escaping quotechars or escapechars 
  123.      * @param lineEnd 
  124.      *            the line feed terminator to use 
  125.      */  
  126.     public CSVWriter(Writer writer, char separator, char quotechar,  
  127.             char escapechar, String lineEnd) {  
  128.         this.rawWriter = writer;  
  129.         this.pw = new PrintWriter(writer);  
  130.         this.separator = separator;  
  131.         this.quotechar = quotechar;  
  132.         this.escapechar = escapechar;  
  133.         this.lineEnd = lineEnd;  
  134.     }  
  135.   
  136.     /** 
  137.      * Writes the entire list to a CSV file. The list is assumed to be a 
  138.      * String[] 
  139.      *  
  140.      * @param allLines 
  141.      *            a List of String[], with each String[] representing a line of 
  142.      *            the file. 
  143.      */  
  144.     @SuppressWarnings("unchecked")  
  145.     public void writeAll(List allLines) {  
  146.   
  147.         for (Iterator iter = allLines.iterator(); iter.hasNext();) {  
  148.             String[] nextLine = (String[]) iter.next();  
  149.             writeNext(nextLine);  
  150.         }  
  151.   
  152.     }  
  153.   
  154.     protected void writeColumnNames(ResultSetMetaData metadata)  
  155.             throws SQLException {  
  156.   
  157.         int columnCount = metadata.getColumnCount();  
  158.   
  159.         String[] nextLine = new String[columnCount];  
  160.         for (int i = 0; i < columnCount; i++) {  
  161.             nextLine[i] = metadata.getColumnName(i + 1);  
  162.         }  
  163.         writeNext(nextLine);  
  164.     }  
  165.   
  166.     /** 
  167.      * Writes the entire ResultSet to a CSV file. 
  168.      *  
  169.      * The caller is responsible for closing the ResultSet. 
  170.      *  
  171.      * @param rs 
  172.      *            the recordset to write 
  173.      * @param includeColumnNames 
  174.      *            true if you want column names in the output, false otherwise 
  175.      *  
  176.      */  
  177.     public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames)  
  178.             throws SQLException, IOException {  
  179.   
  180.         ResultSetMetaData metadata = rs.getMetaData();  
  181.   
  182.         if (includeColumnNames) {  
  183.             writeColumnNames(metadata);  
  184.         }  
  185.   
  186.         int columnCount = metadata.getColumnCount();  
  187.   
  188.         while (rs.next()) {  
  189.             String[] nextLine = new String[columnCount];  
  190.   
  191.             for (int i = 0; i < columnCount; i++) {  
  192.                 nextLine[i] = getColumnValue(rs, metadata.getColumnType(i + 1),  
  193.                         i + 1);  
  194.             }  
  195.   
  196.             writeNext(nextLine);  
  197.         }  
  198.     }  
  199.   
  200.     private static String getColumnValue(ResultSet rs, int colType, int colIndex)  
  201.             throws SQLException, IOException {  
  202.   
  203.         String value = "";  
  204.   
  205.         switch (colType) {  
  206.         case Types.BIT:  
  207.             Object bit = rs.getObject(colIndex);  
  208.             if (bit != null) {  
  209.                 value = String.valueOf(bit);  
  210.             }  
  211.             break;  
  212.         case Types.BOOLEAN:  
  213.             boolean b = rs.getBoolean(colIndex);  
  214.             if (!rs.wasNull()) {  
  215.                 value = Boolean.valueOf(b).toString();  
  216.             }  
  217.             break;  
  218.         case Types.CLOB:  
  219.             Clob c = rs.getClob(colIndex);  
  220.             if (c != null) {  
  221.                 value = read(c);  
  222.             }  
  223.             break;  
  224.         case Types.BIGINT:  
  225.         case Types.DECIMAL:  
  226.         case Types.DOUBLE:  
  227.         case Types.FLOAT:  
  228.         case Types.REAL:  
  229.         case Types.NUMERIC:  
  230.             BigDecimal bd = rs.getBigDecimal(colIndex);  
  231.             if (bd != null) {  
  232.                 value = "" + bd.doubleValue();  
  233.             }  
  234.             break;  
  235.         case Types.INTEGER:  
  236.         case Types.TINYINT:  
  237.         case Types.SMALLINT:  
  238.             int intValue = rs.getInt(colIndex);  
  239.             if (!rs.wasNull()) {  
  240.                 value = "" + intValue;  
  241.             }  
  242.             break;  
  243.         case Types.JAVA_OBJECT:  
  244.             Object obj = rs.getObject(colIndex);  
  245.             if (obj != null) {  
  246.                 value = String.valueOf(obj);  
  247.             }  
  248.             break;  
  249.         case Types.DATE:  
  250.             java.sql.Date date = rs.getDate(colIndex);  
  251.             if (date != null) {  
  252.                 value = DATE_FORMATTER.format(date);  
  253.                 ;  
  254.             }  
  255.             break;  
  256.         case Types.TIME:  
  257.             Time t = rs.getTime(colIndex);  
  258.             if (t != null) {  
  259.                 value = t.toString();  
  260.             }  
  261.             break;  
  262.         case Types.TIMESTAMP:  
  263.             Timestamp tstamp = rs.getTimestamp(colIndex);  
  264.             if (tstamp != null) {  
  265.                 value = TIMESTAMP_FORMATTER.format(tstamp);  
  266.             }  
  267.             break;  
  268.         case Types.LONGVARCHAR:  
  269.         case Types.VARCHAR:  
  270.         case Types.CHAR:  
  271.             value = rs.getString(colIndex);  
  272.             break;  
  273.         default:  
  274.             value = "";  
  275.         }  
  276.   
  277.         if (value == null) {  
  278.             value = "";  
  279.         }  
  280.   
  281.         return value;  
  282.   
  283.     }  
  284.   
  285.     private static String read(Clob c) throws SQLException, IOException {  
  286.         StringBuffer sb = new StringBuffer((int) c.length());  
  287.         Reader r = c.getCharacterStream();  
  288.         char[] cbuf = new char[2048];  
  289.         int n = 0;  
  290.         while ((n = r.read(cbuf, 0, cbuf.length)) != -1) {  
  291.             if (n > 0) {  
  292.                 sb.append(cbuf, 0, n);  
  293.             }  
  294.         }  
  295.         return sb.toString();  
  296.     }  
  297.   
  298.     /** 
  299.      * Writes the next line to the file. 
  300.      *  
  301.      * @param nextLine 
  302.      *            a string array with each comma-separated element as a separate 
  303.      *            entry. 
  304.      */  
  305.     public void writeNext(String[] nextLine) {  
  306.   
  307.         if (nextLine == null)  
  308.             return;  
  309.   
  310.         StringBuffer sb = new StringBuffer();  
  311.         for (int i = 0; i < nextLine.length; i++) {  
  312.   
  313.             if (i != 0) {  
  314.                 sb.append(separator);  
  315.             }  
  316.   
  317.             String nextElement = nextLine[i];  
  318.             if (nextElement == null)  
  319.                 continue;  
  320.             if (quotechar != NO_QUOTE_CHARACTER)  
  321.                 sb.append(quotechar);  
  322.             for (int j = 0; j < nextElement.length(); j++) {  
  323.                 char nextChar = nextElement.charAt(j);  
  324.                 if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) {  
  325.                     sb.append(escapechar).append(nextChar);  
  326.                 } else if (escapechar != NO_ESCAPE_CHARACTER  
  327.                         && nextChar == escapechar) {  
  328.                     sb.append(escapechar).append(nextChar);  
  329.                 } else {  
  330.                     sb.append(nextChar);  
  331.                 }  
  332.             }  
  333.             if (quotechar != NO_QUOTE_CHARACTER)  
  334.                 sb.append(quotechar);  
  335.         }  
  336.   
  337.         sb.append(lineEnd);  
  338.         pw.write(sb.toString());  
  339.   
  340.     }  
  341.   
  342.     /** 
  343.      * Flush underlying stream to writer. 
  344.      *  
  345.      * @throws IOException 
  346.      *             if bad things happen 
  347.      */  
  348.     public void flush() throws IOException {  
  349.   
  350.         pw.flush();  
  351.   
  352.     }  
  353.   
  354.     /** 
  355.      * Close the underlying stream writer flushing any buffered content. 
  356.      *  
  357.      * @throws IOException 
  358.      *             if bad things happen 
  359.      *  
  360.      */  
  361.     public void close() throws IOException {  
  362.         pw.flush();  
  363.         pw.close();  
  364.         rawWriter.close();  
  365.     }  
  366.   
  367. }

    生成文件测试类

  

Java代码   收藏代码
  1. public class CSVWriterTest {  
  2.   
  3.     /** 
  4.      * Test routine for converting output to a string. 
  5.      *  
  6.      * @param args 
  7.      *            the elements of a line of the cvs file 
  8.      * @return a String version 
  9.      * @throws IOException 
  10.      *             if there are problems writing 
  11.      */  
  12.     private String invokeWriter(String[] args) throws IOException {  
  13.         StringWriter sw = new StringWriter();  
  14.         CSVWriter csvw = new CSVWriter(sw, ',''\'');  
  15.         csvw.writeNext(args);  
  16.         return sw.toString();  
  17.     }  
  18.   
  19.     /** 
  20.      * Tests parsing individual lines. 
  21.      *  
  22.      * @throws IOException 
  23.      *             if the reader fails. 
  24.      */  
  25.       
  26.     public void testParseLine() throws IOException {  
  27.   
  28.         // test normal case  
  29.         String[] normal = { "a""b""c" };  
  30.         String output = invokeWriter(normal);  
  31.         assertEquals("'a','b','c'\n", output);  
  32.   
  33.         // test quoted commas  
  34.         String[] quoted = { "a""b,b,b""c" };  
  35.         output = invokeWriter(quoted);  
  36.         assertEquals("'a','b,b,b','c'\n", output);  
  37.   
  38.         // test empty elements  
  39.         String[] empty = {,};  
  40.         output = invokeWriter(empty);  
  41.         assertEquals("\n", output);  
  42.   
  43.         // test multiline quoted  
  44.         String[] multiline = { "This is a \n multiline entry""so is \n this" };  
  45.         output = invokeWriter(multiline);  
  46.         assertEquals("'This is a \n multiline entry','so is \n this'\n", output);  
  47.   
  48.     }  
  49.   
  50.     /** 
  51.      * Test parsing from to a list. 
  52.      *  
  53.      * @throws IOException 
  54.      *             if the reader fails. 
  55.      */  
  56.     @SuppressWarnings("unchecked")  
  57.       
  58.     public void testParseAll() throws IOException {  
  59.   
  60.         List allElements = new ArrayList();  
  61.         String[] line1 = "Name#Phone#Email".split("#");  
  62.         String[] line2 = "Glen#1234#glen@abcd.com".split("#");  
  63.         String[] line3 = "John#5678#john@efgh.com".split("#");  
  64.         allElements.add(line1);  
  65.         allElements.add(line2);  
  66.         allElements.add(line3);  
  67.   
  68.         StringWriter sw = new StringWriter();  
  69.         CSVWriter csvw = new CSVWriter(new FileWriter("d:/test.csv"), ',''\'');  
  70.         csvw.writeAll(allElements);  
  71.   
  72.         //String result = sw.toString();  
  73.         //String[] lines = result.split("\n");  
  74.   
  75.         //assertEquals(3, lines.length);  
  76.   
  77.     }  
  78.   
  79.     /** 
  80.      * Tests the option of having omitting quotes in the output stream. 
  81.      *  
  82.      * @throws IOException 
  83.      *             if bad things happen 
  84.      */  
  85.     public void testNoQuoteChars() throws IOException {  
  86.   
  87.         String[] line = { "Foo""Bar""Baz" };  
  88.         StringWriter sw = new StringWriter();  
  89.         CSVWriter csvw = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR,  
  90.                 CSVWriter.NO_QUOTE_CHARACTER);  
  91.         csvw.writeNext(line);  
  92.         String result = sw.toString();  
  93.   
  94.         assertEquals("Foo,Bar,Baz\n", result);  
  95.     }  
  96.   
  97.     /** 
  98.      * Test null values. 
  99.      *  
  100.      * @throws IOException 
  101.      *             if bad things happen 
  102.      */  
  103.   
  104.     public void testNullValues() throws IOException {  
  105.   
  106.         String[] line = { "Foo"null"Bar""baz" };  
  107.         StringWriter sw = new StringWriter();  
  108.         CSVWriter csvw = new CSVWriter(sw);  
  109.         csvw.writeNext(line);  
  110.         String result = sw.toString();  
  111.   
  112.         assertEquals("\"Foo\",,\"Bar\",\"baz\"\n", result);  
  113.   
  114.     }  
  115.     //@Test  
  116.     //生成CSV文件  
  117.     public void testStreamFlushing() throws IOException {  
  118.   
  119.         String WRITE_FILE = "d:/myfile.csv";  
  120.           
  121.         String[] nextLine = new String[] { "aaaa""bbbb""cccc""dddd" };  
  122.   
  123.         FileWriter fileWriter = new FileWriter(WRITE_FILE);  
  124.         CSVWriter writer = new CSVWriter(fileWriter);  
  125.   
  126.         writer.writeNext(nextLine);  
  127.   
  128.         // If this line is not executed, it is not written in the file.  
  129.         writer.close();  
  130.   
  131.     }  
  132.   
  133.     public void testAlternateEscapeChar() {  
  134.         String[] line = { "Foo""bar's" };  
  135.         StringWriter sw = new StringWriter();  
  136.         CSVWriter csvw = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR,  
  137.                 CSVWriter.DEFAULT_QUOTE_CHARACTER, '\'');  
  138.         csvw.writeNext(line);  
  139.         assertEquals("\"Foo\",\"bar''s\"\n", sw.toString());  
  140.     }  
  141.   
  142.     public void testNoQuotingNoEscaping() {  
  143.         String[] line = { "\"Foo\",\"Bar\"" };  
  144.         StringWriter sw = new StringWriter();  
  145.         CSVWriter csvw = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR,  
  146.                 CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER);  
  147.         csvw.writeNext(line);  
  148.         assertEquals("\"Foo\",\"Bar\"\n", sw.toString());  
  149.     }  
  150.     @Test  
  151.     //测试嵌套的引号  
  152.     public void testNestedQuotes() {  
  153.         String[] data = new String[] { "\"\"""test" };  
  154.         String oracle = new String("\"\"\"\"\"\",\"test\"\n");  
  155.   
  156.         CSVWriter writer = null;  
  157.         File tempFile = null;  
  158.         FileWriter fwriter = null;  
  159.   
  160.         try {  
  161.             tempFile = File.createTempFile("csvWriterTest"".csv");  
  162.             tempFile.deleteOnExit();  
  163.             fwriter = new FileWriter(tempFile);  
  164.             writer = new CSVWriter(fwriter);  
  165.         } catch (IOException e) {  
  166.             fail();  
  167.         }  
  168.   
  169.         // write the test data:  
  170.         writer.writeNext(data);  
  171.   
  172.         try {  
  173.             writer.close();  
  174.         } catch (IOException e) {  
  175.             fail();  
  176.         }  
  177.   
  178.         try {  
  179.             // assert that the writer was also closed.  
  180.             fwriter.flush();  
  181.             fail();  
  182.         } catch (IOException e) {  
  183.             // we should go through here..  
  184.         }  
  185.   
  186.         // read the data and compare.  
  187.         FileReader in = null;  
  188.         try {  
  189.             in = new FileReader(tempFile);  
  190.         } catch (FileNotFoundException e) {  
  191.             fail();  
  192.         }  
  193.   
  194.         StringBuffer fileContents = new StringBuffer();  
  195.         try {  
  196.             int ch;  
  197.             while ((ch = in.read()) != -1) {  
  198.                 fileContents.append((char) ch);  
  199.             }  
  200.             in.close();  
  201.         } catch (IOException e) {  
  202.             fail();  
  203.         }  
  204.   
  205.         assertTrue(oracle.equals(fileContents.toString()));  
  206.     }  
  207.     //@Test  
  208.     public void testAlternateLineFeeds() {  
  209.         String[] line = { "Foo""Bar""baz" };  
  210.         StringWriter sw = new StringWriter();  
  211.         CSVWriter csvw = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR,  
  212.                 CSVWriter.DEFAULT_QUOTE_CHARACTER, "\r");  
  213.         csvw.writeNext(line);  
  214.         String result = sw.toString();  
  215.   
  216.         assertTrue(result.endsWith("\r"));  
  217.   
  218.     }  
  219.   
  220.     /** 
  221.      * The Test Runner for commandline use. 
  222.      *  
  223.      * @param args 
  224.      *            no args required 
  225.      */  
  226.     public static void main(String args[]) {  
  227.         junit.textui.TestRunner.run(CSVWriterTest.class);  
  228.     }  
  229.   
  230. }

其二:EXCEL文件的读取与生成(要用到jxl.jar, 上网可以搜到,我下面附上)

 

Java代码   收藏代码
  1. public class ExcelHandle {  
  2.     public ExcelHandle() {  
  3.     }  
  4.   
  5.     /** 
  6.      * 读取Excel 
  7.      *  
  8.      * @param filePath 
  9.      */  
  10.     public static void readExcel(String filePath) {  
  11.         try {  
  12.             InputStream is = new FileInputStream(filePath);  
  13.             Workbook rwb = Workbook.getWorkbook(is);  
  14.             // Sheet st = rwb.getSheet("0")这里有两种方法获取sheet表,1为名字,而为下标,从0开始  
  15.             Sheet st = rwb.getSheet("original");  
  16.             Cell c00 = st.getCell(00);  
  17.             // 通用的获取cell值的方式,返回字符串  
  18.             String strc00 = c00.getContents();  
  19.             // 获得cell具体类型值的方式  
  20.             if (c00.getType() == CellType.LABEL) {  
  21.                 LabelCell labelc00 = (LabelCell) c00;  
  22.                 strc00 = labelc00.getString();  
  23.             }  
  24.             // 输出  
  25.             System.out.println(strc00);  
  26.             // 关闭  
  27.             rwb.close();  
  28.         } catch (Exception e) {  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32.   
  33.     /** 
  34.      * 输出Excel 
  35.      *  
  36.      * @param os 
  37.      */  
  38.     public static void writeExcel(OutputStream os) {  
  39.         try {  
  40.             /** 
  41.              * 只能通过API提供的工厂方法来创建Workbook,而不能使用WritableWorkbook的构造函数, 
  42.              * 因为类WritableWorkbook的构造函数为protected类型 
  43.              * method(1)直接从目标文件中读取WritableWorkbook wwb = 
  44.              * Workbook.createWorkbook(new File(targetfile)); method(2)如下实例所示 
  45.              * 将WritableWorkbook直接写入到输出流 
  46.              */  
  47.             WritableWorkbook wwb = Workbook.createWorkbook(os);  
  48.             // 创建Excel工作表 指定名称和位置  
  49.             WritableSheet ws = wwb.createSheet("Test Sheet 1"0);  
  50.   
  51.             // **************往工作表中添加数据*****************  
  52.   
  53.             // 1.添加Label对象  
  54.             Label label = new Label(00"this is a label test");  
  55.             ws.addCell(label);  
  56.   
  57.             // 添加带有字型Formatting对象  
  58.             WritableFont wf = new WritableFont(WritableFont.TIMES, 18,  
  59.                     WritableFont.BOLD, true);  
  60.             WritableCellFormat wcf = new WritableCellFormat(wf);  
  61.             Label labelcf = new Label(10"this is a label test", wcf);  
  62.             ws.addCell(labelcf);  
  63.   
  64.             // 添加带有字体颜色的Formatting对象  
  65.             WritableFont wfc = new WritableFont(WritableFont.ARIAL, 10,  
  66.                     WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,  
  67.                     jxl.format.Colour.RED);  
  68.             WritableCellFormat wcfFC = new WritableCellFormat(wfc);  
  69.             Label labelCF = new Label(10"This is a Label Cell", wcfFC);  
  70.             ws.addCell(labelCF);  
  71.   
  72.             // 2.添加Number对象  
  73.             Number labelN = new Number(013.1415926);  
  74.             ws.addCell(labelN);  
  75.   
  76.             // 添加带有formatting的Number对象  
  77.             NumberFormat nf = new NumberFormat("#.##");  
  78.             WritableCellFormat wcfN = new WritableCellFormat(nf);  
  79.             Number labelNF = new jxl.write.Number(113.1415926, wcfN);  
  80.             ws.addCell(labelNF);  
  81.   
  82.             // 3.添加Boolean对象  
  83.             Boolean labelB = new jxl.write.Boolean(02false);  
  84.             ws.addCell(labelB);  
  85.   
  86.             // 4.添加DateTime对象  
  87.             jxl.write.DateTime labelDT = new jxl.write.DateTime(03,  
  88.                     new java.util.Date());  
  89.             ws.addCell(labelDT);  
  90.   
  91.             // 添加带有formatting的DateFormat对象  
  92.             DateFormat df = new DateFormat("dd MM yyyy hh:mm:ss");  
  93.             WritableCellFormat wcfDF = new WritableCellFormat(df);  
  94.             DateTime labelDTF = new DateTime(13new java.util.Date(), wcfDF);  
  95.             ws.addCell(labelDTF);  
  96.   
  97.             // 添加图片对象,jxl只支持png格式图片  
  98.             File image = new File("E:\\2.png");  
  99.             WritableImage wimage = new WritableImage(0122, image);  
  100.             ws.addImage(wimage);  
  101.             // 写入工作表  
  102.             wwb.write();  
  103.             wwb.close();  
  104.         } catch (Exception e) {  
  105.             e.printStackTrace();  
  106.         }  
  107.     }  
  108.   
  109.     /** 
  110.      * 拷贝后,进行修改,其中file1为被copy对象,file2为修改后创建的对象 
  111.      * 尽单元格原有的格式化修饰是不能去掉的,我们还是可以将新的单元格修饰加上去, 以使单元格的内容以不同的形式表现 
  112.      *  
  113.      * @param file1 
  114.      * @param file2 
  115.      */  
  116.     public static void modifyExcel(File file1, File file2) {  
  117.         try {  
  118.             Workbook rwb = Workbook.getWorkbook(file1);  
  119.             WritableWorkbook wwb = Workbook.createWorkbook(file2, rwb);// copy  
  120.             WritableSheet ws = wwb.getSheet(0);  
  121.             WritableCell wc = ws.getWritableCell(00);  
  122.             // 判断单元格的类型,做出相应的转换  
  123.             if (wc.getType() == CellType.LABEL) {  
  124.                 Label label = (Label) wc;  
  125.                 label.setString("The value has been modified");  
  126.             }  
  127.             wwb.write();  
  128.             wwb.close();  
  129.             rwb.close();  
  130.         } catch (Exception e) {  
  131.             e.printStackTrace();  
  132.         }  
  133.     }  
  134.   
  135.     // 测试  
  136.     public static void main(String[] args) {  
  137.         try {  
  138.             // 读Excel  
  139.             //ExcelHandle.readExcel("E:/testRead.xls");  
  140.             // 输出Excel  
  141.             File fileWrite = new File("E:/testWrite.xls");  
  142.             fileWrite.createNewFile();  
  143.             OutputStream os = new FileOutputStream(fileWrite);  
  144.             ExcelHandle.writeExcel(os);  
  145.             // 修改Excel  
  146.             //ExcelHandle.modifyExcel(new File(""), new File(""));  
  147.         } catch (Exception e) {  
  148.             e.printStackTrace();  
  149.         }  
  150.     }  
  151. }

 

   其三:读取CSV文件内容写入到Excel中(此代码含有同步数据库的操作)

Java代码   收藏代码
  1. public static void readCsv(String fileDir, Set targetSet) {  
  2.         System.out.println("执行解析文件............");  
  3.         try {  
  4.             CSVReader csvr = new CSVReader(new FileReader(fileDir), ',''\"',  
  5.                     1);  
  6.             List allElements = csvr.readAll();  
  7.             int size = allElements == null ? 0 : allElements.size();  
  8.             System.out.println("总共有几行:" + size);  
  9.             csvr = new CSVReader(new FileReader(fileDir), ',''\"'1);  
  10.             String[] nextline = null;  
  11.   
  12.             File tempFile = new File("d:/output2.xls");//  
  13.             WritableWorkbook workbook;  
  14.             workbook = Workbook.createWorkbook(tempFile);  
  15.             WritableSheet sheet = workbook.createSheet("kk"1);  
  16.             Label l = null;  
  17.             WritableFont detFont = new WritableFont(WritableFont.ARIAL, 10,  
  18.                     WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,  
  19.                     jxl.format.Colour.BLACK);  
  20.             WritableCellFormat detFormat = new WritableCellFormat(detFont);  
  21.   
  22.             int column = 0;  
  23.             l = new Label(column++, 0"KPI_CODE", detFormat);  
  24.             sheet.addCell(l);  
  25.   
  26.             l = new Label(column++, 0"KPI_DESC", detFormat);  
  27.             sheet.addCell(l);  
  28.   
  29.             l = new Label(column++, 0"KPI_VALUE", detFormat);  
  30.             sheet.addCell(l);  
  31.   
  32.             l = new Label(column++, 0"KPI_MAX", detFormat);  
  33.             sheet.addCell(l);  
  34.   
  35.             l = new Label(column++, 0"KPI_MIN", detFormat);  
  36.             sheet.addCell(l);  
  37.   
  38.             l = new Label(column++, 0"MONTH_ID", detFormat);  
  39.             sheet.addCell(l);  
  40.   
  41.             for (int i = 0; i < size; i++) {  
  42.                 TargetRecordPojo tp = new TargetRecordPojo();  
  43.                 nextline = csvr.readNext();  
  44.                 int len = nextline.length;  
  45.   
  46.                 for (int j = 0; j < len; j++) {  
  47.   
  48.                     l = new Label(j, i + 1, nextline[j], detFormat);  
  49.                     sheet.addCell(l);  
  50.   
  51.                     if (j == 0) {  
  52.                         tp.setTarget_id(nextline[0]);  
  53.   
  54.                         continue;  
  55.                     } else if (j == 1) {  
  56.                         tp.setRemark(nextline[1]);  
  57.   
  58.                         continue;  
  59.   
  60.                     } else if (j == 2) {  
  61.                         tp.setTarget_value(nextline[2]);  
  62.   
  63.                         continue;  
  64.   
  65.                     } else if (j == 3) {  
  66.                         tp.setTarget_data_max(nextline[3]);  
  67.   
  68.                         continue;  
  69.   
  70.                     } else if (j == 4) {  
  71.                         tp.setTarget_data_min(nextline[4]);  
  72.   
  73.                         continue;  
  74.   
  75.                     } else if (j == 5) {  
  76.   
  77.                         tp.setTarget_date(nextline[5]);  
  78.   
  79.                         // tp.setTarget_data_date(DateUtils.dateFormat(date));  
  80.                         continue;  
  81.                     }  
  82.   
  83.                 }  
  84.   
  85.                 targetSet.add(tp);  
  86.   
  87.             }  
  88.             column = 0;  
  89.             sheet.setColumnView(column++, 20);  
  90.             sheet.setColumnView(column++, 20);  
  91.             sheet.setColumnView(column++, 20);  
  92.             sheet.setColumnView(column++, 20);  
  93.             sheet.setColumnView(column++, 20);  
  94.             sheet.setColumnView(column++, 20);  
  95.             workbook.write();  
  96.             workbook.close();  
  97.             FileInputStream fis = new FileInputStream(tempFile);  
  98.             FileOutputStream fos = new FileOutputStream(new File(  
  99.                     "d:/backupfile/backup_" + System.currentTimeMillis()  
  100.                             + ".xls"));  
  101.             byte[] buff = new byte[1024];  
  102.             int len = -1;  
  103.             while ((len = fis.read(buff)) != -1) {  
  104.                 fos.write(buff, 0, len);  
  105.   
  106.             }  
  107.             fis.close();  
  108.             fos.flush();  
  109.             fos.close();  
  110.             tempFile.delete();  
  111.         } catch (FileNotFoundException e) {  
  112.             e.printStackTrace();  
  113.         } catch (IOException e) {  
  114.             // TODO Auto-generated catch block  
  115.             e.printStackTrace();  
  116.         } catch (RowsExceededException e) {  
  117.             // TODO Auto-generated catch block  
  118.             e.printStackTrace();  
  119.         } catch (WriteException e) {  
  120.             // TODO Auto-generated catch block  
  121.             e.printStackTrace();  
  122.         }  
  123.   
  124.     }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值