Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
孙克
/
smf-core
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
流水线
图表
问题
0
合并请求
0
维基
网络
创建新的问题
作业
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 4c2054bd
由
sunke
编写于
2021-07-26 14:02:18 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
上传文件
1 个父辈
9d1e0a8c
隐藏空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
2600 行增加
和
38 行删除
src/main/java/com/neotel/smfcore/common/csv/CsvReader.java
src/main/java/com/neotel/smfcore/common/csv/CsvWriter.java
src/main/java/com/neotel/smfcore/core/barcode/rest/BacodeController.java
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
src/main/java/com/neotel/smfcore/core/storage/rest/StorageController.java
src/main/java/com/neotel/smfcore/security/bean/FileProperties.java
src/main/java/com/neotel/smfcore/security/config/ConfigurerAdapter.java
src/main/resources/config/application-dev.yml
src/main/resources/config/application.yml
src/main/resources/log4j2-spring.xml
src/main/java/com/neotel/smfcore/common/csv/CsvReader.java
0 → 100644
查看文件 @
4c2054b
/*
* Java CSV is a stream based library for reading and writing
* CSV and other delimited data.
*
* Copyright (C) Bruce Dunwiddie bruce@csvreader.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package
com
.
neotel
.
smfcore
.
common
.
csv
;
import
java.io.*
;
import
java.nio.charset.Charset
;
import
java.text.NumberFormat
;
import
java.util.HashMap
;
/**
* A stream based parser for parsing delimited text data from a file or a
* stream.
*/
public
class
CsvReader
{
private
Reader
inputStream
=
null
;
private
String
fileName
=
null
;
// this holds all the values for switches that the user is allowed to set
private
UserSettings
userSettings
=
new
UserSettings
();
private
Charset
charset
=
null
;
private
boolean
useCustomRecordDelimiter
=
false
;
// this will be our working buffer to hold data chunks
// read in from the data file
private
DataBuffer
dataBuffer
=
new
DataBuffer
();
private
ColumnBuffer
columnBuffer
=
new
ColumnBuffer
();
private
RawRecordBuffer
rawBuffer
=
new
RawRecordBuffer
();
private
boolean
[]
isQualified
=
null
;
private
String
rawRecord
=
""
;
private
HeadersHolder
headersHolder
=
new
HeadersHolder
();
// these are all more or less global loop variables
// to keep from needing to pass them all into various
// methods during parsing
private
boolean
startedColumn
=
false
;
private
boolean
startedWithQualifier
=
false
;
private
boolean
hasMoreData
=
true
;
private
char
lastLetter
=
'\0'
;
private
boolean
hasReadNextLine
=
false
;
private
int
columnsCount
=
0
;
private
long
currentRecord
=
0
;
private
String
[]
values
=
new
String
[
StaticSettings
.
INITIAL_COLUMN_COUNT
];
private
boolean
initialized
=
false
;
private
boolean
closed
=
false
;
/**
* Double up the text qualifier to represent an occurance of the text
* qualifier.
*/
public
static
final
int
ESCAPE_MODE_DOUBLED
=
1
;
/**
* Use a backslash character before the text qualifier to represent an
* occurance of the text qualifier.
*/
public
static
final
int
ESCAPE_MODE_BACKSLASH
=
2
;
/**
* Creates a {@link com.csvreader.CsvReader CsvReader} object using a file
* as the data source.
*
* @param fileName
* The path to the file to use as the data source.
* @param delimiter
* The character to use as the column delimiter.
* @param charset
* The {@link Charset Charset} to use while
* parsing the data.
*/
public
CsvReader
(
String
fileName
,
char
delimiter
,
Charset
charset
)
throws
FileNotFoundException
{
if
(
fileName
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter fileName can not be null."
);
}
if
(
charset
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter charset can not be null."
);
}
if
(!
new
File
(
fileName
).
exists
())
{
throw
new
FileNotFoundException
(
"File "
+
fileName
+
" does not exist."
);
}
this
.
fileName
=
fileName
;
this
.
userSettings
.
Delimiter
=
delimiter
;
this
.
charset
=
charset
;
isQualified
=
new
boolean
[
values
.
length
];
}
/**
* Creates a {@link com.csvreader.CsvReader CsvReader} object using a file
* as the data source. Uses ISO-8859-1 as the
* {@link Charset Charset}.
*
* @param fileName
* The path to the file to use as the data source.
* @param delimiter
* The character to use as the column delimiter.
*/
public
CsvReader
(
String
fileName
,
char
delimiter
)
throws
FileNotFoundException
{
this
(
fileName
,
delimiter
,
Charset
.
forName
(
"GBK"
));
}
/**
* Creates a {@link com.csvreader.CsvReader CsvReader} object using a file
* as the data source. Uses a comma as the column delimiter and
* ISO-8859-1 as the {@link Charset Charset}.
*
* @param fileName
* The path to the file to use as the data source.
*/
public
CsvReader
(
String
fileName
)
throws
FileNotFoundException
{
this
(
fileName
,
Letters
.
COMMA
);
}
/**
* Constructs a {@link com.csvreader.CsvReader CsvReader} object using a
* {@link Reader Reader} object as the data source.
*
* @param inputStream
* The stream to use as the data source.
* @param delimiter
* The character to use as the column delimiter.
*/
public
CsvReader
(
Reader
inputStream
,
char
delimiter
)
{
if
(
inputStream
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter inputStream can not be null."
);
}
this
.
inputStream
=
inputStream
;
this
.
userSettings
.
Delimiter
=
delimiter
;
initialized
=
true
;
isQualified
=
new
boolean
[
values
.
length
];
}
/**
* Constructs a {@link com.csvreader.CsvReader CsvReader} object using a
* {@link Reader Reader} object as the data source. Uses a
* comma as the column delimiter.
*
* @param inputStream
* The stream to use as the data source.
*/
public
CsvReader
(
Reader
inputStream
)
{
this
(
inputStream
,
Letters
.
COMMA
);
}
/**
* Constructs a {@link com.csvreader.CsvReader CsvReader} object using an
* {@link InputStream InputStream} object as the data source.
*
* @param inputStream
* The stream to use as the data source.
* @param delimiter
* The character to use as the column delimiter.
* @param charset
* The {@link Charset Charset} to use while
* parsing the data.
*/
public
CsvReader
(
InputStream
inputStream
,
char
delimiter
,
Charset
charset
)
{
this
(
new
InputStreamReader
(
inputStream
,
charset
),
delimiter
);
}
/**
* Constructs a {@link com.csvreader.CsvReader CsvReader} object using an
* {@link InputStream InputStream} object as the data
* source. Uses a comma as the column delimiter.
*
* @param inputStream
* The stream to use as the data source.
* @param charset
* The {@link Charset Charset} to use while
* parsing the data.
*/
public
CsvReader
(
InputStream
inputStream
,
Charset
charset
)
{
this
(
new
InputStreamReader
(
inputStream
,
charset
));
}
public
boolean
getCaptureRawRecord
()
{
return
userSettings
.
CaptureRawRecord
;
}
public
void
setCaptureRawRecord
(
boolean
captureRawRecord
)
{
userSettings
.
CaptureRawRecord
=
captureRawRecord
;
}
public
String
getRawRecord
()
{
return
rawRecord
;
}
/**
* Gets whether leading and trailing whitespace characters are being trimmed
* from non-textqualified column data. Default is true.
*
* @return Whether leading and trailing whitespace characters are being
* trimmed from non-textqualified column data.
*/
public
boolean
getTrimWhitespace
()
{
return
userSettings
.
TrimWhitespace
;
}
/**
* Sets whether leading and trailing whitespace characters should be trimmed
* from non-textqualified column data or not. Default is true.
*
* @param trimWhitespace
* Whether leading and trailing whitespace characters should be
* trimmed from non-textqualified column data or not.
*/
public
void
setTrimWhitespace
(
boolean
trimWhitespace
)
{
userSettings
.
TrimWhitespace
=
trimWhitespace
;
}
/**
* Gets the character being used as the column delimiter. Default is comma,
* ','.
*
* @return The character being used as the column delimiter.
*/
public
char
getDelimiter
()
{
return
userSettings
.
Delimiter
;
}
/**
* Sets the character to use as the column delimiter. Default is comma, ','.
*
* @param delimiter
* The character to use as the column delimiter.
*/
public
void
setDelimiter
(
char
delimiter
)
{
userSettings
.
Delimiter
=
delimiter
;
}
public
char
getRecordDelimiter
()
{
return
userSettings
.
RecordDelimiter
;
}
/**
* Sets the character to use as the record delimiter.
*
* @param recordDelimiter
* The character to use as the record delimiter. Default is
* combination of standard end of line characters for Windows,
* Unix, or Mac.
*/
public
void
setRecordDelimiter
(
char
recordDelimiter
)
{
useCustomRecordDelimiter
=
true
;
userSettings
.
RecordDelimiter
=
recordDelimiter
;
}
/**
* Gets the character to use as a text qualifier in the data.
*
* @return The character to use as a text qualifier in the data.
*/
public
char
getTextQualifier
()
{
return
userSettings
.
TextQualifier
;
}
/**
* Sets the character to use as a text qualifier in the data.
*
* @param textQualifier
* The character to use as a text qualifier in the data.
*/
public
void
setTextQualifier
(
char
textQualifier
)
{
userSettings
.
TextQualifier
=
textQualifier
;
}
/**
* Whether text qualifiers will be used while parsing or not.
*
* @return Whether text qualifiers will be used while parsing or not.
*/
public
boolean
getUseTextQualifier
()
{
return
userSettings
.
UseTextQualifier
;
}
/**
* Sets whether text qualifiers will be used while parsing or not.
*
* @param useTextQualifier
* Whether to use a text qualifier while parsing or not.
*/
public
void
setUseTextQualifier
(
boolean
useTextQualifier
)
{
userSettings
.
UseTextQualifier
=
useTextQualifier
;
}
/**
* Gets the character being used as a comment signal.
*
* @return The character being used as a comment signal.
*/
public
char
getComment
()
{
return
userSettings
.
Comment
;
}
/**
* Sets the character to use as a comment signal.
*
* @param comment
* The character to use as a comment signal.
*/
public
void
setComment
(
char
comment
)
{
userSettings
.
Comment
=
comment
;
}
/**
* Gets whether comments are being looked for while parsing or not.
*
* @return Whether comments are being looked for while parsing or not.
*/
public
boolean
getUseComments
()
{
return
userSettings
.
UseComments
;
}
/**
* Sets whether comments are being looked for while parsing or not.
*
* @param useComments
* Whether comments are being looked for while parsing or not.
*/
public
void
setUseComments
(
boolean
useComments
)
{
userSettings
.
UseComments
=
useComments
;
}
/**
* Gets the current way to escape an occurance of the text qualifier inside
* qualified data.
*
* @return The current way to escape an occurance of the text qualifier
* inside qualified data.
*/
public
int
getEscapeMode
()
{
return
userSettings
.
EscapeMode
;
}
/**
* Sets the current way to escape an occurance of the text qualifier inside
* qualified data.
*
* @param escapeMode
* The way to escape an occurance of the text qualifier inside
* qualified data.
* @exception IllegalArgumentException
* When an illegal value is specified for escapeMode.
*/
public
void
setEscapeMode
(
int
escapeMode
)
throws
IllegalArgumentException
{
if
(
escapeMode
!=
ESCAPE_MODE_DOUBLED
&&
escapeMode
!=
ESCAPE_MODE_BACKSLASH
)
{
throw
new
IllegalArgumentException
(
"Parameter escapeMode must be a valid value."
);
}
userSettings
.
EscapeMode
=
escapeMode
;
}
public
boolean
getSkipEmptyRecords
()
{
return
userSettings
.
SkipEmptyRecords
;
}
public
void
setSkipEmptyRecords
(
boolean
skipEmptyRecords
)
{
userSettings
.
SkipEmptyRecords
=
skipEmptyRecords
;
}
/**
* Safety caution to prevent the parser from using large amounts of memory
* in the case where parsing settings like file encodings don't end up
* matching the actual format of a file. This switch can be turned off if
* the file format is known and tested. With the switch off, the max column
* lengths and max column count per record supported by the parser will
* greatly increase. Default is true.
*
* @return The current setting of the safety switch.
*/
public
boolean
getSafetySwitch
()
{
return
userSettings
.
SafetySwitch
;
}
/**
* Safety caution to prevent the parser from using large amounts of memory
* in the case where parsing settings like file encodings don't end up
* matching the actual format of a file. This switch can be turned off if
* the file format is known and tested. With the switch off, the max column
* lengths and max column count per record supported by the parser will
* greatly increase. Default is true.
*
* @param safetySwitch
*/
public
void
setSafetySwitch
(
boolean
safetySwitch
)
{
userSettings
.
SafetySwitch
=
safetySwitch
;
}
/**
* Gets the count of columns found in this record.
*
* @return The count of columns found in this record.
*/
public
int
getColumnCount
()
{
return
columnsCount
;
}
/**
* Gets the index of the current record.
*
* @return The index of the current record.
*/
public
long
getCurrentRecord
()
{
return
currentRecord
-
1
;
}
/**
* Gets the count of headers read in by a previous call to
* {@link com.csvreader.CsvReader#readHeaders readHeaders()}.
*
* @return The count of headers read in by a previous call to
* {@link com.csvreader.CsvReader#readHeaders readHeaders()}.
*/
public
int
getHeaderCount
()
{
return
headersHolder
.
Length
;
}
/**
* Returns the header values as a string array.
*
* @return The header values as a String array.
* @exception IOException
* Thrown if this object has already been closed.
*/
public
String
[]
getHeaders
()
throws
IOException
{
checkClosed
();
if
(
headersHolder
.
Headers
==
null
)
{
return
null
;
}
else
{
// use clone here to prevent the outside code from
// setting values on the array directly, which would
// throw off the index lookup based on header name
String
[]
clone
=
new
String
[
headersHolder
.
Length
];
System
.
arraycopy
(
headersHolder
.
Headers
,
0
,
clone
,
0
,
headersHolder
.
Length
);
return
clone
;
}
}
public
void
setHeaders
(
String
[]
headers
)
{
headersHolder
.
Headers
=
headers
;
headersHolder
.
IndexByName
.
clear
();
if
(
headers
!=
null
)
{
headersHolder
.
Length
=
headers
.
length
;
}
else
{
headersHolder
.
Length
=
0
;
}
// use headersHolder.Length here in case headers is null
for
(
int
i
=
0
;
i
<
headersHolder
.
Length
;
i
++)
{
headersHolder
.
IndexByName
.
put
(
headers
[
i
],
new
Integer
(
i
));
}
}
public
String
[]
getValues
()
throws
IOException
{
checkClosed
();
// need to return a clone, and can't use clone because values.Length
// might be greater than columnsCount
String
[]
clone
=
new
String
[
columnsCount
];
System
.
arraycopy
(
values
,
0
,
clone
,
0
,
columnsCount
);
return
clone
;
}
/**
* Returns the current column value for a given column index.
*
* @param columnIndex
* The index of the column.
* @return The current column value.
* @exception IOException
* Thrown if this object has already been closed.
*/
public
String
get
(
int
columnIndex
)
throws
IOException
{
checkClosed
();
if
(
columnIndex
>
-
1
&&
columnIndex
<
columnsCount
)
{
return
values
[
columnIndex
];
}
else
{
return
""
;
}
}
/**
* Returns the current column value for a given column header name.
*
* @param headerName
* The header name of the column.
* @return The current column value.
* @exception IOException
* Thrown if this object has already been closed.
*/
public
String
get
(
String
headerName
)
throws
IOException
{
checkClosed
();
return
get
(
getIndex
(
headerName
));
}
/**
* Creates a {@link com.csvreader.CsvReader CsvReader} object using a string
* of data as the source. Uses ISO-8859-1 as the
* {@link Charset Charset}.
*
* @param data
* The String of data to use as the source.
* @return A {@link com.csvreader.CsvReader CsvReader} object using the
* String of data as the source.
*/
public
static
CsvReader
parse
(
String
data
)
{
if
(
data
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter data can not be null."
);
}
return
new
CsvReader
(
new
StringReader
(
data
));
}
/**
* Reads another record.
*
* @return Whether another record was successfully read or not.
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
public
boolean
readRecord
()
throws
IOException
{
checkClosed
();
columnsCount
=
0
;
rawBuffer
.
Position
=
0
;
dataBuffer
.
LineStart
=
dataBuffer
.
Position
;
hasReadNextLine
=
false
;
// check to see if we've already found the end of data
if
(
hasMoreData
)
{
// loop over the data stream until the end of data is found
// or the end of the record is found
do
{
if
(
dataBuffer
.
Position
==
dataBuffer
.
Count
)
{
checkDataLength
();
}
else
{
startedWithQualifier
=
false
;
// grab the current letter as a char
char
currentLetter
=
dataBuffer
.
Buffer
[
dataBuffer
.
Position
];
if
(
userSettings
.
UseTextQualifier
&&
currentLetter
==
userSettings
.
TextQualifier
)
{
// this will be a text qualified column, so
// we need to set startedWithQualifier to make it
// enter the seperate branch to handle text
// qualified columns
lastLetter
=
currentLetter
;
// read qualified
startedColumn
=
true
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
startedWithQualifier
=
true
;
boolean
lastLetterWasQualifier
=
false
;
char
escapeChar
=
userSettings
.
TextQualifier
;
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
)
{
escapeChar
=
Letters
.
BACKSLASH
;
}
boolean
eatingTrailingJunk
=
false
;
boolean
lastLetterWasEscape
=
false
;
boolean
readingComplexEscape
=
false
;
int
escape
=
ComplexEscape
.
UNICODE
;
int
escapeLength
=
0
;
char
escapeValue
=
(
char
)
0
;
dataBuffer
.
Position
++;
do
{
if
(
dataBuffer
.
Position
==
dataBuffer
.
Count
)
{
checkDataLength
();
}
else
{
// grab the current letter as a char
currentLetter
=
dataBuffer
.
Buffer
[
dataBuffer
.
Position
];
if
(
eatingTrailingJunk
)
{
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
if
(
currentLetter
==
userSettings
.
Delimiter
)
{
endColumn
();
}
else
if
((!
useCustomRecordDelimiter
&&
(
currentLetter
==
Letters
.
CR
||
currentLetter
==
Letters
.
LF
))
||
(
useCustomRecordDelimiter
&&
currentLetter
==
userSettings
.
RecordDelimiter
))
{
endColumn
();
endRecord
();
}
}
else
if
(
readingComplexEscape
)
{
escapeLength
++;
switch
(
escape
)
{
case
ComplexEscape
.
UNICODE
:
escapeValue
*=
(
char
)
16
;
escapeValue
+=
hexToDec
(
currentLetter
);
if
(
escapeLength
==
4
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
OCTAL
:
escapeValue
*=
(
char
)
8
;
escapeValue
+=
(
char
)
(
currentLetter
-
'0'
);
if
(
escapeLength
==
3
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
DECIMAL
:
escapeValue
*=
(
char
)
10
;
escapeValue
+=
(
char
)
(
currentLetter
-
'0'
);
if
(
escapeLength
==
3
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
HEX
:
escapeValue
*=
(
char
)
16
;
escapeValue
+=
hexToDec
(
currentLetter
);
if
(
escapeLength
==
2
)
{
readingComplexEscape
=
false
;
}
break
;
}
if
(!
readingComplexEscape
)
{
appendLetter
(
escapeValue
);
}
else
{
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
}
}
else
if
(
currentLetter
==
userSettings
.
TextQualifier
)
{
if
(
lastLetterWasEscape
)
{
lastLetterWasEscape
=
false
;
lastLetterWasQualifier
=
false
;
}
else
{
updateCurrentValue
();
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_DOUBLED
)
{
lastLetterWasEscape
=
true
;
}
lastLetterWasQualifier
=
true
;
}
}
else
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
&&
lastLetterWasEscape
)
{
switch
(
currentLetter
)
{
case
'n'
:
appendLetter
(
Letters
.
LF
);
break
;
case
'r'
:
appendLetter
(
Letters
.
CR
);
break
;
case
't'
:
appendLetter
(
Letters
.
TAB
);
break
;
case
'b'
:
appendLetter
(
Letters
.
BACKSPACE
);
break
;
case
'f'
:
appendLetter
(
Letters
.
FORM_FEED
);
break
;
case
'e'
:
appendLetter
(
Letters
.
ESCAPE
);
break
;
case
'v'
:
appendLetter
(
Letters
.
VERTICAL_TAB
);
break
;
case
'a'
:
appendLetter
(
Letters
.
ALERT
);
break
;
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
escape
=
ComplexEscape
.
OCTAL
;
readingComplexEscape
=
true
;
escapeLength
=
1
;
escapeValue
=
(
char
)
(
currentLetter
-
'0'
);
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
break
;
case
'u'
:
case
'x'
:
case
'o'
:
case
'd'
:
case
'U'
:
case
'X'
:
case
'O'
:
case
'D'
:
switch
(
currentLetter
)
{
case
'u'
:
case
'U'
:
escape
=
ComplexEscape
.
UNICODE
;
break
;
case
'x'
:
case
'X'
:
escape
=
ComplexEscape
.
HEX
;
break
;
case
'o'
:
case
'O'
:
escape
=
ComplexEscape
.
OCTAL
;
break
;
case
'd'
:
case
'D'
:
escape
=
ComplexEscape
.
DECIMAL
;
break
;
}
readingComplexEscape
=
true
;
escapeLength
=
0
;
escapeValue
=
(
char
)
0
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
break
;
default
:
break
;
}
lastLetterWasEscape
=
false
;
// can only happen for ESCAPE_MODE_BACKSLASH
}
else
if
(
currentLetter
==
escapeChar
)
{
updateCurrentValue
();
lastLetterWasEscape
=
true
;
}
else
{
if
(
lastLetterWasQualifier
)
{
if
(
currentLetter
==
userSettings
.
Delimiter
)
{
endColumn
();
}
else
if
((!
useCustomRecordDelimiter
&&
(
currentLetter
==
Letters
.
CR
||
currentLetter
==
Letters
.
LF
))
||
(
useCustomRecordDelimiter
&&
currentLetter
==
userSettings
.
RecordDelimiter
))
{
endColumn
();
endRecord
();
}
else
{
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
eatingTrailingJunk
=
true
;
}
// make sure to clear the flag for next
// run of the loop
lastLetterWasQualifier
=
false
;
}
}
// keep track of the last letter because we need
// it for several key decisions
lastLetter
=
currentLetter
;
if
(
startedColumn
)
{
dataBuffer
.
Position
++;
if
(
userSettings
.
SafetySwitch
&&
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
+
columnBuffer
.
Position
>
100000
)
{
close
();
throw
new
IOException
(
"Maximum column length of 100,000 exceeded in column "
+
NumberFormat
.
getIntegerInstance
()
.
format
(
columnsCount
)
+
" in record "
+
NumberFormat
.
getIntegerInstance
()
.
format
(
currentRecord
)
+
". Set the SafetySwitch property to false"
+
" if you're expecting column lengths greater than 100,000 characters to"
+
" avoid this error."
);
}
}
}
// end else
}
while
(
hasMoreData
&&
startedColumn
);
}
else
if
(
currentLetter
==
userSettings
.
Delimiter
)
{
// we encountered a column with no data, so
// just send the end column
lastLetter
=
currentLetter
;
endColumn
();
}
else
if
(
useCustomRecordDelimiter
&&
currentLetter
==
userSettings
.
RecordDelimiter
)
{
// this will skip blank lines
if
(
startedColumn
||
columnsCount
>
0
||
!
userSettings
.
SkipEmptyRecords
)
{
endColumn
();
endRecord
();
}
else
{
dataBuffer
.
LineStart
=
dataBuffer
.
Position
+
1
;
}
lastLetter
=
currentLetter
;
}
else
if
(!
useCustomRecordDelimiter
&&
(
currentLetter
==
Letters
.
CR
||
currentLetter
==
Letters
.
LF
))
{
// this will skip blank lines
if
(
startedColumn
||
columnsCount
>
0
||
(!
userSettings
.
SkipEmptyRecords
&&
(
currentLetter
==
Letters
.
CR
||
lastLetter
!=
Letters
.
CR
)))
{
endColumn
();
endRecord
();
}
else
{
dataBuffer
.
LineStart
=
dataBuffer
.
Position
+
1
;
}
lastLetter
=
currentLetter
;
}
else
if
(
userSettings
.
UseComments
&&
columnsCount
==
0
&&
currentLetter
==
userSettings
.
Comment
)
{
// encountered a comment character at the beginning of
// the line so just ignore the rest of the line
lastLetter
=
currentLetter
;
skipLine
();
}
else
if
(
userSettings
.
TrimWhitespace
&&
(
currentLetter
==
Letters
.
SPACE
||
currentLetter
==
Letters
.
TAB
))
{
// do nothing, this will trim leading whitespace
// for both text qualified columns and non
startedColumn
=
true
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
}
else
{
// since the letter wasn't a special letter, this
// will be the first letter of our current column
startedColumn
=
true
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
;
boolean
lastLetterWasBackslash
=
false
;
boolean
readingComplexEscape
=
false
;
int
escape
=
ComplexEscape
.
UNICODE
;
int
escapeLength
=
0
;
char
escapeValue
=
(
char
)
0
;
boolean
firstLoop
=
true
;
do
{
if
(!
firstLoop
&&
dataBuffer
.
Position
==
dataBuffer
.
Count
)
{
checkDataLength
();
}
else
{
if
(!
firstLoop
)
{
// grab the current letter as a char
currentLetter
=
dataBuffer
.
Buffer
[
dataBuffer
.
Position
];
}
if
(!
userSettings
.
UseTextQualifier
&&
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
&&
currentLetter
==
Letters
.
BACKSLASH
)
{
if
(
lastLetterWasBackslash
)
{
lastLetterWasBackslash
=
false
;
}
else
{
updateCurrentValue
();
lastLetterWasBackslash
=
true
;
}
}
else
if
(
readingComplexEscape
)
{
escapeLength
++;
switch
(
escape
)
{
case
ComplexEscape
.
UNICODE
:
escapeValue
*=
(
char
)
16
;
escapeValue
+=
hexToDec
(
currentLetter
);
if
(
escapeLength
==
4
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
OCTAL
:
escapeValue
*=
(
char
)
8
;
escapeValue
+=
(
char
)
(
currentLetter
-
'0'
);
if
(
escapeLength
==
3
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
DECIMAL
:
escapeValue
*=
(
char
)
10
;
escapeValue
+=
(
char
)
(
currentLetter
-
'0'
);
if
(
escapeLength
==
3
)
{
readingComplexEscape
=
false
;
}
break
;
case
ComplexEscape
.
HEX
:
escapeValue
*=
(
char
)
16
;
escapeValue
+=
hexToDec
(
currentLetter
);
if
(
escapeLength
==
2
)
{
readingComplexEscape
=
false
;
}
break
;
}
if
(!
readingComplexEscape
)
{
appendLetter
(
escapeValue
);
}
else
{
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
}
}
else
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
&&
lastLetterWasBackslash
)
{
switch
(
currentLetter
)
{
case
'n'
:
appendLetter
(
Letters
.
LF
);
break
;
case
'r'
:
appendLetter
(
Letters
.
CR
);
break
;
case
't'
:
appendLetter
(
Letters
.
TAB
);
break
;
case
'b'
:
appendLetter
(
Letters
.
BACKSPACE
);
break
;
case
'f'
:
appendLetter
(
Letters
.
FORM_FEED
);
break
;
case
'e'
:
appendLetter
(
Letters
.
ESCAPE
);
break
;
case
'v'
:
appendLetter
(
Letters
.
VERTICAL_TAB
);
break
;
case
'a'
:
appendLetter
(
Letters
.
ALERT
);
break
;
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
escape
=
ComplexEscape
.
OCTAL
;
readingComplexEscape
=
true
;
escapeLength
=
1
;
escapeValue
=
(
char
)
(
currentLetter
-
'0'
);
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
break
;
case
'u'
:
case
'x'
:
case
'o'
:
case
'd'
:
case
'U'
:
case
'X'
:
case
'O'
:
case
'D'
:
switch
(
currentLetter
)
{
case
'u'
:
case
'U'
:
escape
=
ComplexEscape
.
UNICODE
;
break
;
case
'x'
:
case
'X'
:
escape
=
ComplexEscape
.
HEX
;
break
;
case
'o'
:
case
'O'
:
escape
=
ComplexEscape
.
OCTAL
;
break
;
case
'd'
:
case
'D'
:
escape
=
ComplexEscape
.
DECIMAL
;
break
;
}
readingComplexEscape
=
true
;
escapeLength
=
0
;
escapeValue
=
(
char
)
0
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
break
;
default
:
break
;
}
lastLetterWasBackslash
=
false
;
}
else
{
if
(
currentLetter
==
userSettings
.
Delimiter
)
{
endColumn
();
}
else
if
((!
useCustomRecordDelimiter
&&
(
currentLetter
==
Letters
.
CR
||
currentLetter
==
Letters
.
LF
))
||
(
useCustomRecordDelimiter
&&
currentLetter
==
userSettings
.
RecordDelimiter
))
{
endColumn
();
endRecord
();
}
}
// keep track of the last letter because we need
// it for several key decisions
lastLetter
=
currentLetter
;
firstLoop
=
false
;
if
(
startedColumn
)
{
dataBuffer
.
Position
++;
if
(
userSettings
.
SafetySwitch
&&
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
+
columnBuffer
.
Position
>
100000
)
{
close
();
throw
new
IOException
(
"Maximum column length of 100,000 exceeded in column "
+
NumberFormat
.
getIntegerInstance
()
.
format
(
columnsCount
)
+
" in record "
+
NumberFormat
.
getIntegerInstance
()
.
format
(
currentRecord
)
+
". Set the SafetySwitch property to false"
+
" if you're expecting column lengths greater than 100,000 characters to"
+
" avoid this error."
);
}
}
}
// end else
}
while
(
hasMoreData
&&
startedColumn
);
}
if
(
hasMoreData
)
{
dataBuffer
.
Position
++;
}
}
// end else
}
while
(
hasMoreData
&&
!
hasReadNextLine
);
// check to see if we hit the end of the file
// without processing the current record
if
(
startedColumn
||
lastLetter
==
userSettings
.
Delimiter
)
{
endColumn
();
endRecord
();
}
}
if
(
userSettings
.
CaptureRawRecord
)
{
if
(
hasMoreData
)
{
if
(
rawBuffer
.
Position
==
0
)
{
rawRecord
=
new
String
(
dataBuffer
.
Buffer
,
dataBuffer
.
LineStart
,
dataBuffer
.
Position
-
dataBuffer
.
LineStart
-
1
);
}
else
{
rawRecord
=
new
String
(
rawBuffer
.
Buffer
,
0
,
rawBuffer
.
Position
)
+
new
String
(
dataBuffer
.
Buffer
,
dataBuffer
.
LineStart
,
dataBuffer
.
Position
-
dataBuffer
.
LineStart
-
1
);
}
}
else
{
// for hasMoreData to ever be false, all data would have had to
// have been
// copied to the raw buffer
rawRecord
=
new
String
(
rawBuffer
.
Buffer
,
0
,
rawBuffer
.
Position
);
}
}
else
{
rawRecord
=
""
;
}
return
hasReadNextLine
;
}
/**
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
private
void
checkDataLength
()
throws
IOException
{
if
(!
initialized
)
{
if
(
fileName
!=
null
)
{
inputStream
=
new
BufferedReader
(
new
InputStreamReader
(
new
FileInputStream
(
fileName
),
charset
),
StaticSettings
.
MAX_FILE_BUFFER_SIZE
);
}
charset
=
null
;
initialized
=
true
;
}
updateCurrentValue
();
if
(
userSettings
.
CaptureRawRecord
&&
dataBuffer
.
Count
>
0
)
{
if
(
rawBuffer
.
Buffer
.
length
-
rawBuffer
.
Position
<
dataBuffer
.
Count
-
dataBuffer
.
LineStart
)
{
int
newLength
=
rawBuffer
.
Buffer
.
length
+
Math
.
max
(
dataBuffer
.
Count
-
dataBuffer
.
LineStart
,
rawBuffer
.
Buffer
.
length
);
char
[]
holder
=
new
char
[
newLength
];
System
.
arraycopy
(
rawBuffer
.
Buffer
,
0
,
holder
,
0
,
rawBuffer
.
Position
);
rawBuffer
.
Buffer
=
holder
;
}
System
.
arraycopy
(
dataBuffer
.
Buffer
,
dataBuffer
.
LineStart
,
rawBuffer
.
Buffer
,
rawBuffer
.
Position
,
dataBuffer
.
Count
-
dataBuffer
.
LineStart
);
rawBuffer
.
Position
+=
dataBuffer
.
Count
-
dataBuffer
.
LineStart
;
}
try
{
dataBuffer
.
Count
=
inputStream
.
read
(
dataBuffer
.
Buffer
,
0
,
dataBuffer
.
Buffer
.
length
);
}
catch
(
IOException
ex
)
{
close
();
throw
ex
;
}
// if no more data could be found, set flag stating that
// the end of the data was found
if
(
dataBuffer
.
Count
==
-
1
)
{
hasMoreData
=
false
;
}
dataBuffer
.
Position
=
0
;
dataBuffer
.
LineStart
=
0
;
dataBuffer
.
ColumnStart
=
0
;
}
/**
* Read the first record of data as column headers.
*
* @return Whether the header record was successfully read or not.
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
public
boolean
readHeaders
()
throws
IOException
{
boolean
result
=
readRecord
();
// copy the header data from the column array
// to the header string array
headersHolder
.
Length
=
columnsCount
;
headersHolder
.
Headers
=
new
String
[
columnsCount
];
for
(
int
i
=
0
;
i
<
headersHolder
.
Length
;
i
++)
{
String
columnValue
=
get
(
i
);
headersHolder
.
Headers
[
i
]
=
columnValue
;
// if there are duplicate header names, we will save the last one
headersHolder
.
IndexByName
.
put
(
columnValue
,
new
Integer
(
i
));
}
if
(
result
)
{
currentRecord
--;
}
columnsCount
=
0
;
return
result
;
}
/**
* Returns the column header value for a given column index.
*
* @param columnIndex
* The index of the header column being requested.
* @return The value of the column header at the given column index.
* @exception IOException
* Thrown if this object has already been closed.
*/
public
String
getHeader
(
int
columnIndex
)
throws
IOException
{
checkClosed
();
// check to see if we have read the header record yet
// check to see if the column index is within the bounds
// of our header array
if
(
columnIndex
>
-
1
&&
columnIndex
<
headersHolder
.
Length
)
{
// return the processed header data for this column
return
headersHolder
.
Headers
[
columnIndex
];
}
else
{
return
""
;
}
}
public
boolean
isQualified
(
int
columnIndex
)
throws
IOException
{
checkClosed
();
if
(
columnIndex
<
columnsCount
&&
columnIndex
>
-
1
)
{
return
isQualified
[
columnIndex
];
}
else
{
return
false
;
}
}
/**
* @exception IOException
* Thrown if a very rare extreme exception occurs during
* parsing, normally resulting from improper data format.
*/
private
void
endColumn
()
throws
IOException
{
String
currentValue
=
""
;
// must be called before setting startedColumn = false
if
(
startedColumn
)
{
if
(
columnBuffer
.
Position
==
0
)
{
if
(
dataBuffer
.
ColumnStart
<
dataBuffer
.
Position
)
{
int
lastLetter
=
dataBuffer
.
Position
-
1
;
if
(
userSettings
.
TrimWhitespace
&&
!
startedWithQualifier
)
{
while
(
lastLetter
>=
dataBuffer
.
ColumnStart
&&
(
dataBuffer
.
Buffer
[
lastLetter
]
==
Letters
.
SPACE
||
dataBuffer
.
Buffer
[
lastLetter
]
==
Letters
.
TAB
))
{
lastLetter
--;
}
}
currentValue
=
new
String
(
dataBuffer
.
Buffer
,
dataBuffer
.
ColumnStart
,
lastLetter
-
dataBuffer
.
ColumnStart
+
1
);
}
}
else
{
updateCurrentValue
();
int
lastLetter
=
columnBuffer
.
Position
-
1
;
if
(
userSettings
.
TrimWhitespace
&&
!
startedWithQualifier
)
{
while
(
lastLetter
>=
0
&&
(
columnBuffer
.
Buffer
[
lastLetter
]
==
Letters
.
SPACE
||
columnBuffer
.
Buffer
[
lastLetter
]
==
Letters
.
SPACE
))
{
lastLetter
--;
}
}
currentValue
=
new
String
(
columnBuffer
.
Buffer
,
0
,
lastLetter
+
1
);
}
}
columnBuffer
.
Position
=
0
;
startedColumn
=
false
;
if
(
columnsCount
>=
100000
&&
userSettings
.
SafetySwitch
)
{
close
();
throw
new
IOException
(
"Maximum column count of 100,000 exceeded in record "
+
NumberFormat
.
getIntegerInstance
().
format
(
currentRecord
)
+
". Set the SafetySwitch property to false"
+
" if you're expecting more than 100,000 columns per record to"
+
" avoid this error."
);
}
// check to see if our current holder array for
// column chunks is still big enough to handle another
// column chunk
if
(
columnsCount
==
values
.
length
)
{
// holder array needs to grow to be able to hold another column
int
newLength
=
values
.
length
*
2
;
String
[]
holder
=
new
String
[
newLength
];
System
.
arraycopy
(
values
,
0
,
holder
,
0
,
values
.
length
);
values
=
holder
;
boolean
[]
qualifiedHolder
=
new
boolean
[
newLength
];
System
.
arraycopy
(
isQualified
,
0
,
qualifiedHolder
,
0
,
isQualified
.
length
);
isQualified
=
qualifiedHolder
;
}
values
[
columnsCount
]
=
currentValue
;
isQualified
[
columnsCount
]
=
startedWithQualifier
;
currentValue
=
""
;
columnsCount
++;
}
private
void
appendLetter
(
char
letter
)
{
if
(
columnBuffer
.
Position
==
columnBuffer
.
Buffer
.
length
)
{
int
newLength
=
columnBuffer
.
Buffer
.
length
*
2
;
char
[]
holder
=
new
char
[
newLength
];
System
.
arraycopy
(
columnBuffer
.
Buffer
,
0
,
holder
,
0
,
columnBuffer
.
Position
);
columnBuffer
.
Buffer
=
holder
;
}
columnBuffer
.
Buffer
[
columnBuffer
.
Position
++]
=
letter
;
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
}
private
void
updateCurrentValue
()
{
if
(
startedColumn
&&
dataBuffer
.
ColumnStart
<
dataBuffer
.
Position
)
{
if
(
columnBuffer
.
Buffer
.
length
-
columnBuffer
.
Position
<
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
)
{
int
newLength
=
columnBuffer
.
Buffer
.
length
+
Math
.
max
(
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
,
columnBuffer
.
Buffer
.
length
);
char
[]
holder
=
new
char
[
newLength
];
System
.
arraycopy
(
columnBuffer
.
Buffer
,
0
,
holder
,
0
,
columnBuffer
.
Position
);
columnBuffer
.
Buffer
=
holder
;
}
System
.
arraycopy
(
dataBuffer
.
Buffer
,
dataBuffer
.
ColumnStart
,
columnBuffer
.
Buffer
,
columnBuffer
.
Position
,
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
);
columnBuffer
.
Position
+=
dataBuffer
.
Position
-
dataBuffer
.
ColumnStart
;
}
dataBuffer
.
ColumnStart
=
dataBuffer
.
Position
+
1
;
}
/**
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
private
void
endRecord
()
throws
IOException
{
// this flag is used as a loop exit condition
// during parsing
hasReadNextLine
=
true
;
currentRecord
++;
}
/**
* Gets the corresponding column index for a given column header name.
*
* @param headerName
* The header name of the column.
* @return The column index for the given column header name. Returns
* -1 if not found.
* @exception IOException
* Thrown if this object has already been closed.
*/
public
int
getIndex
(
String
headerName
)
throws
IOException
{
checkClosed
();
Object
indexValue
=
headersHolder
.
IndexByName
.
get
(
headerName
);
if
(
indexValue
!=
null
)
{
return
((
Integer
)
indexValue
).
intValue
();
}
else
{
return
-
1
;
}
}
public
int
getIndex
(
String
...
headerNameAlias
){
for
(
String
headName:
headerNameAlias
)
{
try
{
int
index
=
getIndex
(
headName
);
if
(
index
!=
-
1
){
return
index
;
}
}
catch
(
Exception
e
){
}
}
return
-
1
;
}
/**
* Skips the next record of data by parsing each column. Does not
* increment
* {@link com.csvreader.CsvReader#getCurrentRecord getCurrentRecord()}.
*
* @return Whether another record was successfully skipped or not.
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
public
boolean
skipRecord
()
throws
IOException
{
checkClosed
();
boolean
recordRead
=
false
;
if
(
hasMoreData
)
{
recordRead
=
readRecord
();
if
(
recordRead
)
{
currentRecord
--;
}
}
return
recordRead
;
}
/**
* Skips the next line of data using the standard end of line characters and
* does not do any column delimited parsing.
*
* @return Whether a line was successfully skipped or not.
* @exception IOException
* Thrown if an error occurs while reading data from the
* source stream.
*/
public
boolean
skipLine
()
throws
IOException
{
checkClosed
();
// clear public column values for current line
columnsCount
=
0
;
boolean
skippedLine
=
false
;
if
(
hasMoreData
)
{
boolean
foundEol
=
false
;
do
{
if
(
dataBuffer
.
Position
==
dataBuffer
.
Count
)
{
checkDataLength
();
}
else
{
skippedLine
=
true
;
// grab the current letter as a char
char
currentLetter
=
dataBuffer
.
Buffer
[
dataBuffer
.
Position
];
if
(
currentLetter
==
Letters
.
CR
||
currentLetter
==
Letters
.
LF
)
{
foundEol
=
true
;
}
// keep track of the last letter because we need
// it for several key decisions
lastLetter
=
currentLetter
;
if
(!
foundEol
)
{
dataBuffer
.
Position
++;
}
}
// end else
}
while
(
hasMoreData
&&
!
foundEol
);
columnBuffer
.
Position
=
0
;
dataBuffer
.
LineStart
=
dataBuffer
.
Position
+
1
;
}
rawBuffer
.
Position
=
0
;
rawRecord
=
""
;
return
skippedLine
;
}
/**
* Closes and releases all related resources.
*/
public
void
close
()
{
if
(!
closed
)
{
close
(
true
);
closed
=
true
;
}
}
/**
*
*/
private
void
close
(
boolean
closing
)
{
if
(!
closed
)
{
if
(
closing
)
{
charset
=
null
;
headersHolder
.
Headers
=
null
;
headersHolder
.
IndexByName
=
null
;
dataBuffer
.
Buffer
=
null
;
columnBuffer
.
Buffer
=
null
;
rawBuffer
.
Buffer
=
null
;
}
try
{
if
(
initialized
)
{
inputStream
.
close
();
}
}
catch
(
Exception
e
)
{
// just eat the exception
}
inputStream
=
null
;
closed
=
true
;
}
}
/**
* @exception IOException
* Thrown if this object has already been closed.
*/
private
void
checkClosed
()
throws
IOException
{
if
(
closed
)
{
throw
new
IOException
(
"This instance of the CsvReader class has already been closed."
);
}
}
/**
*
*/
protected
void
finalize
()
{
close
(
false
);
}
private
class
ComplexEscape
{
private
static
final
int
UNICODE
=
1
;
private
static
final
int
OCTAL
=
2
;
private
static
final
int
DECIMAL
=
3
;
private
static
final
int
HEX
=
4
;
}
private
static
char
hexToDec
(
char
hex
)
{
char
result
;
if
(
hex
>=
'a'
)
{
result
=
(
char
)
(
hex
-
'a'
+
10
);
}
else
if
(
hex
>=
'A'
)
{
result
=
(
char
)
(
hex
-
'A'
+
10
);
}
else
{
result
=
(
char
)
(
hex
-
'0'
);
}
return
result
;
}
private
class
DataBuffer
{
public
char
[]
Buffer
;
public
int
Position
;
// / <summary>
// / How much usable data has been read into the stream,
// / which will not always be as long as Buffer.Length.
// / </summary>
public
int
Count
;
// / <summary>
// / The position of the cursor in the buffer when the
// / current column was started or the last time data
// / was moved out to the column buffer.
// / </summary>
public
int
ColumnStart
;
public
int
LineStart
;
public
DataBuffer
()
{
Buffer
=
new
char
[
StaticSettings
.
MAX_BUFFER_SIZE
];
Position
=
0
;
Count
=
0
;
ColumnStart
=
0
;
LineStart
=
0
;
}
}
private
class
ColumnBuffer
{
public
char
[]
Buffer
;
public
int
Position
;
public
ColumnBuffer
()
{
Buffer
=
new
char
[
StaticSettings
.
INITIAL_COLUMN_BUFFER_SIZE
];
Position
=
0
;
}
}
private
class
RawRecordBuffer
{
public
char
[]
Buffer
;
public
int
Position
;
public
RawRecordBuffer
()
{
Buffer
=
new
char
[
StaticSettings
.
INITIAL_COLUMN_BUFFER_SIZE
*
StaticSettings
.
INITIAL_COLUMN_COUNT
];
Position
=
0
;
}
}
private
class
Letters
{
public
static
final
char
LF
=
'\n'
;
public
static
final
char
CR
=
'\r'
;
public
static
final
char
QUOTE
=
'"'
;
public
static
final
char
COMMA
=
','
;
public
static
final
char
SPACE
=
' '
;
public
static
final
char
TAB
=
'\t'
;
public
static
final
char
POUND
=
'#'
;
public
static
final
char
BACKSLASH
=
'\\'
;
public
static
final
char
NULL
=
'\0'
;
public
static
final
char
BACKSPACE
=
'\b'
;
public
static
final
char
FORM_FEED
=
'\f'
;
public
static
final
char
ESCAPE
=
'\
u001B
'
;
// ASCII/ANSI escape
public
static
final
char
VERTICAL_TAB
=
'\
u000B
'
;
public
static
final
char
ALERT
=
'\u0007'
;
}
private
class
UserSettings
{
// having these as publicly accessible members will prevent
// the overhead of the method call that exists on properties
public
boolean
CaseSensitive
;
public
char
TextQualifier
;
public
boolean
TrimWhitespace
;
public
boolean
UseTextQualifier
;
public
char
Delimiter
;
public
char
RecordDelimiter
;
public
char
Comment
;
public
boolean
UseComments
;
public
int
EscapeMode
;
public
boolean
SafetySwitch
;
public
boolean
SkipEmptyRecords
;
public
boolean
CaptureRawRecord
;
public
UserSettings
()
{
CaseSensitive
=
true
;
TextQualifier
=
Letters
.
QUOTE
;
TrimWhitespace
=
true
;
UseTextQualifier
=
true
;
Delimiter
=
Letters
.
COMMA
;
RecordDelimiter
=
Letters
.
NULL
;
Comment
=
Letters
.
POUND
;
UseComments
=
false
;
EscapeMode
=
CsvReader
.
ESCAPE_MODE_DOUBLED
;
SafetySwitch
=
true
;
SkipEmptyRecords
=
true
;
CaptureRawRecord
=
true
;
}
}
private
class
HeadersHolder
{
public
String
[]
Headers
;
public
int
Length
;
public
HashMap
IndexByName
;
public
HeadersHolder
()
{
Headers
=
null
;
Length
=
0
;
IndexByName
=
new
HashMap
();
}
}
private
class
StaticSettings
{
// these are static instead of final so they can be changed in unit test
// isn't visible outside this class and is only accessed once during
// CsvReader construction
public
static
final
int
MAX_BUFFER_SIZE
=
1024
;
public
static
final
int
MAX_FILE_BUFFER_SIZE
=
4
*
1024
;
public
static
final
int
INITIAL_COLUMN_COUNT
=
10
;
public
static
final
int
INITIAL_COLUMN_BUFFER_SIZE
=
50
;
}
}
\ No newline at end of file
src/main/java/com/neotel/smfcore/common/csv/CsvWriter.java
0 → 100644
查看文件 @
4c2054b
/*
* Java CSV is a stream based library for reading and writing
* CSV and other delimited data.
*
* Copyright (C) Bruce Dunwiddie bruce@csvreader.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package
com
.
neotel
.
smfcore
.
common
.
csv
;
import
java.io.*
;
import
java.nio.charset.Charset
;
/**
* A stream based writer for writing delimited text data to a file or a stream.
*/
public
class
CsvWriter
{
private
Writer
outputStream
=
null
;
private
String
fileName
=
null
;
private
boolean
firstColumn
=
true
;
private
boolean
useCustomRecordDelimiter
=
false
;
private
Charset
charset
=
null
;
// this holds all the values for switches that the user is allowed to set
private
UserSettings
userSettings
=
new
UserSettings
();
private
boolean
initialized
=
false
;
private
boolean
closed
=
false
;
private
String
systemRecordDelimiter
=
System
.
getProperty
(
"line.separator"
);
/**
* Double up the text qualifier to represent an occurrence of the text
* qualifier.
*/
public
static
final
int
ESCAPE_MODE_DOUBLED
=
1
;
/**
* Use a backslash character before the text qualifier to represent an
* occurrence of the text qualifier.
*/
public
static
final
int
ESCAPE_MODE_BACKSLASH
=
2
;
/**
* Creates a {@link com.csvreader.CsvWriter CsvWriter} object using a file
* as the data destination.
*
* @param fileName
* The path to the file to output the data.
* @param delimiter
* The character to use as the column delimiter.
* @param charset
* The {@link Charset Charset} to use while
* writing the data.
*/
public
CsvWriter
(
String
fileName
,
char
delimiter
,
Charset
charset
)
{
if
(
fileName
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter fileName can not be null."
);
}
if
(
charset
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter charset can not be null."
);
}
this
.
fileName
=
fileName
;
userSettings
.
Delimiter
=
delimiter
;
this
.
charset
=
charset
;
}
/**
* Creates a {@link com.csvreader.CsvWriter CsvWriter} object using a file
* as the data destination. Uses a comma as the column delimiter and
* ISO-8859-1 as the {@link Charset Charset}.
*
* @param fileName
* The path to the file to output the data.
*/
public
CsvWriter
(
String
fileName
)
{
this
(
fileName
,
Letters
.
COMMA
,
Charset
.
forName
(
"ISO-8859-1"
));
}
/**
* Creates a {@link com.csvreader.CsvWriter CsvWriter} object using a Writer
* to write data to.
*
* @param outputStream
* The stream to write the column delimited data to.
* @param delimiter
* The character to use as the column delimiter.
*/
public
CsvWriter
(
Writer
outputStream
,
char
delimiter
)
{
if
(
outputStream
==
null
)
{
throw
new
IllegalArgumentException
(
"Parameter outputStream can not be null."
);
}
this
.
outputStream
=
outputStream
;
userSettings
.
Delimiter
=
delimiter
;
initialized
=
true
;
}
/**
* Creates a {@link com.csvreader.CsvWriter CsvWriter} object using an
* OutputStream to write data to.
*
* @param outputStream
* The stream to write the column delimited data to.
* @param delimiter
* The character to use as the column delimiter.
* @param charset
* The {@link Charset Charset} to use while
* writing the data.
*/
public
CsvWriter
(
OutputStream
outputStream
,
char
delimiter
,
Charset
charset
)
{
this
(
new
OutputStreamWriter
(
outputStream
,
charset
),
delimiter
);
}
/**
* Gets the character being used as the column delimiter.
*
* @return The character being used as the column delimiter.
*/
public
char
getDelimiter
()
{
return
userSettings
.
Delimiter
;
}
/**
* Sets the character to use as the column delimiter.
*
* @param delimiter
* The character to use as the column delimiter.
*/
public
void
setDelimiter
(
char
delimiter
)
{
userSettings
.
Delimiter
=
delimiter
;
}
public
char
getRecordDelimiter
()
{
return
userSettings
.
RecordDelimiter
;
}
/**
* Sets the character to use as the record delimiter.
*
* @param recordDelimiter
* The character to use as the record delimiter. Default is
* combination of standard end of line characters for Windows,
* Unix, or Mac.
*/
public
void
setRecordDelimiter
(
char
recordDelimiter
)
{
useCustomRecordDelimiter
=
true
;
userSettings
.
RecordDelimiter
=
recordDelimiter
;
}
/**
* Gets the character to use as a text qualifier in the data.
*
* @return The character to use as a text qualifier in the data.
*/
public
char
getTextQualifier
()
{
return
userSettings
.
TextQualifier
;
}
/**
* Sets the character to use as a text qualifier in the data.
*
* @param textQualifier
* The character to use as a text qualifier in the data.
*/
public
void
setTextQualifier
(
char
textQualifier
)
{
userSettings
.
TextQualifier
=
textQualifier
;
}
/**
* Whether text qualifiers will be used while writing data or not.
*
* @return Whether text qualifiers will be used while writing data or not.
*/
public
boolean
getUseTextQualifier
()
{
return
userSettings
.
UseTextQualifier
;
}
/**
* Sets whether text qualifiers will be used while writing data or not.
*
* @param useTextQualifier
* Whether to use a text qualifier while writing data or not.
*/
public
void
setUseTextQualifier
(
boolean
useTextQualifier
)
{
userSettings
.
UseTextQualifier
=
useTextQualifier
;
}
public
int
getEscapeMode
()
{
return
userSettings
.
EscapeMode
;
}
public
void
setEscapeMode
(
int
escapeMode
)
{
userSettings
.
EscapeMode
=
escapeMode
;
}
public
void
setComment
(
char
comment
)
{
userSettings
.
Comment
=
comment
;
}
public
char
getComment
()
{
return
userSettings
.
Comment
;
}
/**
* Whether fields will be surrounded by the text qualifier even if the
* qualifier is not necessarily needed to escape this field.
*
* @return Whether fields will be forced to be qualified or not.
*/
public
boolean
getForceQualifier
()
{
return
userSettings
.
ForceQualifier
;
}
/**
* Use this to force all fields to be surrounded by the text qualifier even
* if the qualifier is not necessarily needed to escape this field. Default
* is false.
*
* @param forceQualifier
* Whether to force the fields to be qualified or not.
*/
public
void
setForceQualifier
(
boolean
forceQualifier
)
{
userSettings
.
ForceQualifier
=
forceQualifier
;
}
/**
* Writes another column of data to this record.
*
* @param content
* The data for the new column.
* @param preserveSpaces
* Whether to preserve leading and trailing whitespace in this
* column of data.
* @exception IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
write
(
String
content
,
boolean
preserveSpaces
)
throws
IOException
{
checkClosed
();
checkInit
();
if
(
content
==
null
)
{
content
=
""
;
}
if
(!
firstColumn
)
{
outputStream
.
write
(
userSettings
.
Delimiter
);
}
boolean
textQualify
=
userSettings
.
ForceQualifier
;
if
(!
preserveSpaces
&&
content
.
length
()
>
0
)
{
content
=
content
.
trim
();
}
if
(!
textQualify
&&
userSettings
.
UseTextQualifier
&&
(
content
.
indexOf
(
userSettings
.
TextQualifier
)
>
-
1
||
content
.
indexOf
(
userSettings
.
Delimiter
)
>
-
1
||
(!
useCustomRecordDelimiter
&&
(
content
.
indexOf
(
Letters
.
LF
)
>
-
1
||
content
.
indexOf
(
Letters
.
CR
)
>
-
1
))
||
(
useCustomRecordDelimiter
&&
content
.
indexOf
(
userSettings
.
RecordDelimiter
)
>
-
1
)
||
(
firstColumn
&&
content
.
length
()
>
0
&&
content
.
charAt
(
0
)
==
userSettings
.
Comment
)
||
// check for empty first column, which if on its own line must
// be qualified or the line will be skipped
(
firstColumn
&&
content
.
length
()
==
0
)))
{
textQualify
=
true
;
}
if
(
userSettings
.
UseTextQualifier
&&
!
textQualify
&&
content
.
length
()
>
0
&&
preserveSpaces
)
{
char
firstLetter
=
content
.
charAt
(
0
);
if
(
firstLetter
==
Letters
.
SPACE
||
firstLetter
==
Letters
.
TAB
)
{
textQualify
=
true
;
}
if
(!
textQualify
&&
content
.
length
()
>
1
)
{
char
lastLetter
=
content
.
charAt
(
content
.
length
()
-
1
);
if
(
lastLetter
==
Letters
.
SPACE
||
lastLetter
==
Letters
.
TAB
)
{
textQualify
=
true
;
}
}
}
if
(
textQualify
)
{
outputStream
.
write
(
userSettings
.
TextQualifier
);
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
)
{
content
=
replace
(
content
,
""
+
Letters
.
BACKSLASH
,
""
+
Letters
.
BACKSLASH
+
Letters
.
BACKSLASH
);
content
=
replace
(
content
,
""
+
userSettings
.
TextQualifier
,
""
+
Letters
.
BACKSLASH
+
userSettings
.
TextQualifier
);
}
else
{
content
=
replace
(
content
,
""
+
userSettings
.
TextQualifier
,
""
+
userSettings
.
TextQualifier
+
userSettings
.
TextQualifier
);
}
}
else
if
(
userSettings
.
EscapeMode
==
ESCAPE_MODE_BACKSLASH
)
{
content
=
replace
(
content
,
""
+
Letters
.
BACKSLASH
,
""
+
Letters
.
BACKSLASH
+
Letters
.
BACKSLASH
);
content
=
replace
(
content
,
""
+
userSettings
.
Delimiter
,
""
+
Letters
.
BACKSLASH
+
userSettings
.
Delimiter
);
if
(
useCustomRecordDelimiter
)
{
content
=
replace
(
content
,
""
+
userSettings
.
RecordDelimiter
,
""
+
Letters
.
BACKSLASH
+
userSettings
.
RecordDelimiter
);
}
else
{
content
=
replace
(
content
,
""
+
Letters
.
CR
,
""
+
Letters
.
BACKSLASH
+
Letters
.
CR
);
content
=
replace
(
content
,
""
+
Letters
.
LF
,
""
+
Letters
.
BACKSLASH
+
Letters
.
LF
);
}
if
(
firstColumn
&&
content
.
length
()
>
0
&&
content
.
charAt
(
0
)
==
userSettings
.
Comment
)
{
if
(
content
.
length
()
>
1
)
{
content
=
""
+
Letters
.
BACKSLASH
+
userSettings
.
Comment
+
content
.
substring
(
1
);
}
else
{
content
=
""
+
Letters
.
BACKSLASH
+
userSettings
.
Comment
;
}
}
}
outputStream
.
write
(
content
);
if
(
textQualify
)
{
outputStream
.
write
(
userSettings
.
TextQualifier
);
}
firstColumn
=
false
;
}
/**
* Writes another column of data to this record. Does not preserve
* leading and trailing whitespace in this column of data.
*
* @param content
* The data for the new column.
* @exception IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
write
(
String
content
)
throws
IOException
{
write
(
content
,
false
);
}
public
void
writeComment
(
String
commentText
)
throws
IOException
{
checkClosed
();
checkInit
();
outputStream
.
write
(
userSettings
.
Comment
);
outputStream
.
write
(
commentText
);
if
(
useCustomRecordDelimiter
)
{
outputStream
.
write
(
userSettings
.
RecordDelimiter
);
}
else
{
outputStream
.
write
(
systemRecordDelimiter
);
}
firstColumn
=
true
;
}
/**
* Writes a new record using the passed in array of values.
*
* @param values
* Values to be written.
*
* @param preserveSpaces
* Whether to preserver leading and trailing spaces in columns
* while writing out to the record or not.
*
* @throws IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
writeRecord
(
String
[]
values
,
boolean
preserveSpaces
)
throws
IOException
{
if
(
values
!=
null
&&
values
.
length
>
0
)
{
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
write
(
values
[
i
],
preserveSpaces
);
}
endRecord
();
}
}
/**
* Writes a new record using the passed in array of values.
*
* @param values
* Values to be written.
*
* @throws IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
writeRecord
(
String
[]
values
)
throws
IOException
{
writeRecord
(
values
,
false
);
}
/**
* Ends the current record by sending the record delimiter.
*
* @exception IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
endRecord
()
throws
IOException
{
checkClosed
();
checkInit
();
if
(
useCustomRecordDelimiter
)
{
outputStream
.
write
(
userSettings
.
RecordDelimiter
);
}
else
{
outputStream
.
write
(
systemRecordDelimiter
);
}
firstColumn
=
true
;
}
/**
*
*/
private
void
checkInit
()
throws
IOException
{
if
(!
initialized
)
{
if
(
fileName
!=
null
)
{
outputStream
=
new
BufferedWriter
(
new
OutputStreamWriter
(
new
FileOutputStream
(
fileName
,
true
),
charset
));
}
initialized
=
true
;
}
}
/**
* Clears all buffers for the current writer and causes any buffered data to
* be written to the underlying device.
* @exception IOException
* Thrown if an error occurs while writing data to the
* destination stream.
*/
public
void
flush
()
throws
IOException
{
outputStream
.
flush
();
}
/**
* Closes and releases all related resources.
*/
public
void
close
()
{
if
(!
closed
)
{
close
(
true
);
closed
=
true
;
}
}
/**
*
*/
private
void
close
(
boolean
closing
)
{
if
(!
closed
)
{
if
(
closing
)
{
charset
=
null
;
}
try
{
if
(
initialized
)
{
outputStream
.
close
();
}
}
catch
(
Exception
e
)
{
// just eat the exception
}
outputStream
=
null
;
closed
=
true
;
}
}
/**
*
*/
private
void
checkClosed
()
throws
IOException
{
if
(
closed
)
{
throw
new
IOException
(
"This instance of the CsvWriter class has already been closed."
);
}
}
/**
*
*/
protected
void
finalize
()
{
close
(
false
);
}
private
class
Letters
{
public
static
final
char
LF
=
'\n'
;
public
static
final
char
CR
=
'\r'
;
public
static
final
char
QUOTE
=
'"'
;
public
static
final
char
COMMA
=
','
;
public
static
final
char
SPACE
=
' '
;
public
static
final
char
TAB
=
'\t'
;
public
static
final
char
POUND
=
'#'
;
public
static
final
char
BACKSLASH
=
'\\'
;
public
static
final
char
NULL
=
'\0'
;
}
private
class
UserSettings
{
// having these as publicly accessible members will prevent
// the overhead of the method call that exists on properties
public
char
TextQualifier
;
public
boolean
UseTextQualifier
;
public
char
Delimiter
;
public
char
RecordDelimiter
;
public
char
Comment
;
public
int
EscapeMode
;
public
boolean
ForceQualifier
;
public
UserSettings
()
{
TextQualifier
=
Letters
.
QUOTE
;
UseTextQualifier
=
true
;
Delimiter
=
Letters
.
COMMA
;
RecordDelimiter
=
Letters
.
NULL
;
Comment
=
Letters
.
POUND
;
EscapeMode
=
ESCAPE_MODE_DOUBLED
;
ForceQualifier
=
false
;
}
}
public
static
String
replace
(
String
original
,
String
pattern
,
String
replace
)
{
final
int
len
=
pattern
.
length
();
int
found
=
original
.
indexOf
(
pattern
);
if
(
found
>
-
1
)
{
StringBuffer
sb
=
new
StringBuffer
();
int
start
=
0
;
while
(
found
!=
-
1
)
{
sb
.
append
(
original
.
substring
(
start
,
found
));
sb
.
append
(
replace
);
start
=
found
+
len
;
found
=
original
.
indexOf
(
pattern
,
start
);
}
sb
.
append
(
original
.
substring
(
start
));
return
sb
.
toString
();
}
else
{
return
original
;
}
}
}
\ No newline at end of file
src/main/java/com/neotel/smfcore/core/barcode/rest/BacodeController.java
查看文件 @
4c2054b
package
com
.
neotel
.
smfcore
.
core
.
barcode
.
rest
;
import
com.google.common.collect.Lists
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.ResultBean
;
import
com.neotel.smfcore.common.csv.CsvReader
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.utils.FileUtil
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeDto
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeSettingDto
;
...
...
@@ -12,6 +16,7 @@ import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import
com.neotel.smfcore.core.barcode.service.po.Barcode
;
import
com.neotel.smfcore.core.device.util.DataCache
;
import
com.neotel.smfcore.core.system.service.po.Settings
;
import
com.neotel.smfcore.security.bean.FileProperties
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.RequiredArgsConstructor
;
...
...
@@ -22,10 +27,13 @@ import org.springframework.data.mongodb.core.query.Query;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -46,6 +54,9 @@ public class BacodeController {
@Autowired
private
final
DataCache
dataCache
;
@Autowired
private
final
FileProperties
properties
;
@ApiOperation
(
"导出条码数据"
)
@GetMapping
(
value
=
"/download"
)
public
void
download
(
HttpServletResponse
response
,
BarcodeQueryCriteria
criteria
)
throws
Exception
{
...
...
@@ -129,4 +140,80 @@ public class BacodeController {
//修改设置
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
}
@ApiOperation
(
"上传条码数据"
)
@PostMapping
(
value
=
"/upload"
)
public
ResultBean
upload
(
@RequestParam
MultipartFile
uploadFile
)
throws
Exception
{
String
image
=
"csv"
;
String
fileType
=
FileUtil
.
getExtensionName
(
uploadFile
.
getOriginalFilename
());
if
(
fileType
!=
null
&&
!
image
.
contains
(
fileType
)){
throw
new
BadRequestException
(
"文件格式错误!, 仅支持 "
+
image
+
" 格式"
);
}
File
folder
=
new
File
(
properties
.
getPath
(),
"pos"
);
File
file
=
FileUtil
.
upload
(
uploadFile
,
folder
.
getAbsolutePath
());
String
resultMsg
=
handleBarcode
(
file
.
getAbsolutePath
());
return
ResultBean
.
newOkResult
(
resultMsg
);
}
protected
String
handleBarcode
(
String
fileURL
)
throws
Exception
{
log
.
info
(
"开始读取文件:"
+
fileURL
);
CsvReader
csvRead
=
new
CsvReader
(
fileURL
);
csvRead
.
setSkipEmptyRecords
(
true
);
//忽略空行
csvRead
.
setTrimWhitespace
(
true
);
//去除空格
csvRead
.
readHeaders
();
int
riIndex
=
csvRead
.
getIndex
(
"条码"
,
"RI"
);
int
pnIndex
=
csvRead
.
getIndex
(
"物编"
,
"PN"
);
int
qtyIndex
=
csvRead
.
getIndex
(
"数量"
,
"QTY"
);
int
wIndex
=
csvRead
.
getIndex
(
"宽度"
,
"W"
);
int
hIndex
=
csvRead
.
getIndex
(
"高度"
,
"H"
);
int
spIndex
=
csvRead
.
getIndex
(
"供应商"
,
"SP"
,
"supplier"
);
int
row
=
1
;
int
newRowCount
=
0
;
int
updateRowCount
=
0
;
List
<
Barcode
>
list
=
Lists
.
newArrayList
();
while
(
csvRead
.
readRecord
()){
row
++;
String
[]
lineValues
=
csvRead
.
getValues
();
String
ri
=
lineValues
[
riIndex
];
String
pn
=
lineValues
[
pnIndex
];
if
(
ObjectUtils
.
isEmpty
(
pn
)
||
ObjectUtils
.
isEmpty
(
ri
)){
log
.
warn
(
"第"
+
row
+
"行中有空白内容,此行忽略"
);
continue
;
}
Barcode
barcode
=
barcodeManager
.
findByBarcode
(
ri
);
if
(
barcode
==
null
){
newRowCount
++;
barcode
=
new
Barcode
();
barcode
.
setBarcode
(
ri
);
}
else
{
updateRowCount
++;
}
barcode
.
setPartNumber
(
pn
);
if
(
qtyIndex
!=
-
1
){
String
qtyStr
=
lineValues
[
qtyIndex
];
barcode
.
setAmount
(
Double
.
valueOf
(
qtyStr
).
intValue
());
}
if
(
wIndex
!=
-
1
){
String
wStr
=
lineValues
[
wIndex
];
barcode
.
setPlateSize
(
Double
.
valueOf
(
wStr
).
intValue
());
}
if
(
hIndex
!=
-
1
){
String
hStr
=
lineValues
[
hIndex
];
barcode
.
setHeight
(
Double
.
valueOf
(
hStr
).
intValue
());
}
if
(
spIndex
!=
-
1
){
String
supplier
=
lineValues
[
spIndex
];
barcode
.
setProvider
(
supplier
);
}
barcodeManager
.
save
(
barcode
);
}
String
msg
=
"共["
+
row
+
"]行数据:新增【"
+
newRowCount
+
"】更新【"
+
updateRowCount
+
"】个"
;
log
.
info
(
msg
);
return
msg
;
}
}
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
查看文件 @
4c2054b
...
...
@@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.List
;
import
java.util.Set
;
...
...
@@ -75,6 +76,13 @@ public class OrderController {
// userService.download(userService.queryAll(criteria), response);
// }
@ApiOperation
(
"上传工单"
)
@PostMapping
(
value
=
"/upload"
)
public
ResultBean
updateAvatar
(
@RequestParam
MultipartFile
orderFile
){
return
null
;
}
@ApiOperation
(
"工单出库"
)
@PostMapping
(
value
=
"/out"
)
@PreAuthorize
(
"@el.check('order:out')"
)
...
...
src/main/java/com/neotel/smfcore/core/storage/rest/StorageController.java
查看文件 @
4c2054b
package
com
.
neotel
.
smfcore
.
core
.
storage
.
rest
;
import
com.google.common.base.Strings
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.ResultBean
;
import
com.neotel.smfcore.common.csv.CsvReader
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.common.exception.ValidateException
;
import
com.neotel.smfcore.common.utils.FileUtil
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.core.device.util.DataCache
;
import
com.neotel.smfcore.core.storage.rest.dto.StorageDto
;
import
com.neotel.smfcore.core.storage.rest.mapstruct.StorageMapper
;
import
com.neotel.smfcore.core.storage.rest.query.StorageQueryCriteria
;
import
com.neotel.smfcore.core.storage.service.manager.IStorageManager
;
import
com.neotel.smfcore.core.storage.service.manager.IStoragePosManager
;
import
com.neotel.smfcore.core.storage.service.po.Storage
;
import
com.neotel.smfcore.core.storage.service.po.StoragePos
;
import
com.neotel.smfcore.security.bean.FileProperties
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.RequiredArgsConstructor
;
...
...
@@ -20,8 +29,10 @@ import org.springframework.http.ResponseEntity;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Set
;
...
...
@@ -37,6 +48,14 @@ public class StorageController {
@Autowired
private
final
StorageMapper
storageMapper
;
@Autowired
private
final
FileProperties
properties
;
@Autowired
private
final
IStoragePosManager
storagePosManager
;
@Autowired
private
final
DataCache
dataCache
;
@ApiOperation
(
"查询料仓"
)
@GetMapping
...
...
@@ -82,4 +101,95 @@ public class StorageController {
}
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
}
@ApiOperation
(
"上传库位信息"
)
@PostMapping
(
value
=
"/{storageId}/upload"
)
public
ResultBean
upload
(
@PathVariable
String
storageId
,
@RequestParam
MultipartFile
uploadFile
)
throws
Exception
{
// 验证文件上传的格式
String
image
=
"csv"
;
String
fileType
=
FileUtil
.
getExtensionName
(
uploadFile
.
getOriginalFilename
());
if
(
fileType
!=
null
&&
!
image
.
contains
(
fileType
)){
throw
new
BadRequestException
(
"文件格式错误!, 仅支持 "
+
image
+
" 格式"
);
}
File
folder
=
new
File
(
properties
.
getPath
(),
"pos"
);
File
file
=
FileUtil
.
upload
(
uploadFile
,
folder
.
getAbsolutePath
());
String
resultMsg
=
handleStoragePos
(
file
.
getAbsolutePath
(),
storageId
);
return
ResultBean
.
newOkResult
(
resultMsg
);
}
/**
*
*/
protected
String
handleStoragePos
(
String
fileURL
,
String
storageId
)
throws
Exception
{
log
.
info
(
"开始更新料仓【"
+
storageId
+
"】的位置信息"
);
if
(
Strings
.
isNullOrEmpty
(
storageId
))
{
log
.
error
(
"Storage id is null"
);
throw
new
ValidateException
(
"storage.error.notExist"
);
}
Storage
storage
=
storageManager
.
get
(
storageId
);
if
(
storage
==
null
)
{
log
.
error
(
"Storage id is not exist"
);
throw
new
ValidateException
(
"storage.error.notExist"
);
}
CsvReader
csvRead
=
new
CsvReader
(
fileURL
);
csvRead
.
setSkipEmptyRecords
(
true
);
//忽略空行
csvRead
.
setTrimWhitespace
(
true
);
//去除空格
csvRead
.
readHeaders
();
int
posIndex
=
csvRead
.
getIndex
(
"位置"
,
"pos"
);
if
(
posIndex
==
-
1
){
log
.
info
(
"未包含【位置】或【pos】列"
);
throw
new
ValidateException
(
"必须包含[位置]列"
);
}
int
priIndex
=
csvRead
.
getIndex
(
"优先级"
,
"pri"
);
if
(
priIndex
==
-
1
){
log
.
info
(
"未包含【优先级】或【pri】列"
);
throw
new
ValidateException
(
"必须包含[优先级]列"
);
}
int
hIndex
=
csvRead
.
getIndex
(
"高度"
,
"h"
);
if
(
hIndex
==
-
1
){
log
.
info
(
"未包含【高度】或【h】列"
);
throw
new
ValidateException
(
"必须包含【高度】列"
);
}
int
wIndex
=
csvRead
.
getIndex
(
"宽度"
,
"w"
);
if
(
wIndex
==
-
1
){
log
.
info
(
"未包含【宽度】或【w】列"
);
throw
new
ValidateException
(
"必须包含【宽度】列"
);
}
int
row
=
1
;
int
newRowCount
=
0
;
int
updateRowCount
=
0
;
while
(
csvRead
.
readRecord
()){
row
++;
String
[]
lineValues
=
csvRead
.
getValues
();
String
posName
=
lineValues
[
posIndex
];
String
priorityStr
=
lineValues
[
priIndex
];
String
hStr
=
lineValues
[
hIndex
];
String
wStr
=
lineValues
[
wIndex
];
if
(
posName
.
isEmpty
()
||
hStr
.
isEmpty
()
||
wStr
.
isEmpty
()){
log
.
warn
(
"第"
+
row
+
"行中有空白内容,此行忽略"
);
continue
;
}
StoragePos
posInfo
=
storagePosManager
.
getByPosName
(
posName
);
if
(
posInfo
==
null
){
posInfo
=
new
StoragePos
();
posInfo
.
setPosName
(
posName
);
newRowCount
++;
}
else
{
updateRowCount
++;
}
posInfo
.
setH
(
Integer
.
valueOf
(
hStr
));
posInfo
.
setW
(
Integer
.
valueOf
(
wStr
));
if
(!
Strings
.
isNullOrEmpty
(
priorityStr
)){
posInfo
.
setPriority
(
Double
.
valueOf
(
priorityStr
));
}
storagePosManager
.
save
(
posInfo
);
}
dataCache
.
reloadStorage
(
storage
);
String
msg
=
"读取到["
+
row
+
"]行数据:新增【"
+
newRowCount
+
"】更新【"
+
updateRowCount
+
"】"
;
log
.
info
(
msg
);
return
msg
;
}
}
src/main/java/com/neotel/smfcore/security/bean/FileProperties.java
查看文件 @
4c2054b
...
...
@@ -28,19 +28,13 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties
(
prefix
=
"file"
)
public
class
FileProperties
{
/** 文件大小限制 */
private
Long
maxSize
;
private
String
mac
;
/** 头像大小限制 */
private
Long
avatarMaxSize
;
private
String
linux
;
private
ElPath
mac
;
private
String
windows
;
private
ElPath
linux
;
private
ElPath
windows
;
public
ElPath
getPath
(){
public
String
getPath
(){
String
os
=
System
.
getProperty
(
"os.name"
);
if
(
os
.
toLowerCase
().
startsWith
(
ElAdminConstant
.
WIN
))
{
return
windows
;
...
...
@@ -49,12 +43,4 @@ public class FileProperties {
}
return
linux
;
}
@Data
public
static
class
ElPath
{
private
String
path
;
private
String
avatar
;
}
}
src/main/java/com/neotel/smfcore/security/config/ConfigurerAdapter.java
查看文件 @
4c2054b
...
...
@@ -77,10 +77,7 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
@Override
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
FileProperties
.
ElPath
path
=
properties
.
getPath
();
String
avatarUtl
=
"file:"
+
path
.
getAvatar
().
replace
(
"\\"
,
"/"
);
String
pathUtl
=
"file:"
+
path
.
getPath
().
replace
(
"\\"
,
"/"
);
registry
.
addResourceHandler
(
"/avatar/**"
).
addResourceLocations
(
avatarUtl
).
setCachePeriod
(
0
);
String
pathUtl
=
"file:"
+
properties
.
getPath
().
replace
(
"\\"
,
"/"
);
registry
.
addResourceHandler
(
"/file/**"
).
addResourceLocations
(
pathUtl
).
setCachePeriod
(
0
);
registry
.
addResourceHandler
(
"/**"
).
addResourceLocations
(
"classpath:/META-INF/resources/"
).
setCachePeriod
(
0
);
}
...
...
src/main/resources/config/application-dev.yml
查看文件 @
4c2054b
...
...
@@ -59,17 +59,4 @@ swagger:
ip
:
local-parsing
:
true
# 文件存储路径
file
:
mac
:
path
:
~/file/
avatar
:
~/avatar/
linux
:
path
:
/home/eladmin/file/
avatar
:
/home/eladmin/avatar/
windows
:
path
:
C:\eladmin\file\
avatar
:
C:\eladmin\avatar\
# 文件大小 /M
maxSize
:
100
avatarMaxSize
:
5
src/main/resources/config/application.yml
查看文件 @
4c2054b
...
...
@@ -5,6 +5,12 @@ hella:
host
:
port
:
9900
# 文件存储路径
file
:
mac
:
~/file/
linux
:
/home/smf/file/
windows
:
C:\smf\file\
spring
:
freemarker
:
check-template-location
:
false
...
...
src/main/resources/log4j2-spring.xml
查看文件 @
4c2054b
...
...
@@ -22,7 +22,7 @@
<logger
name=
"ro"
level=
"WARN"
>
</logger>
<root
level=
"INFO"
>
<
!--<appender-ref ref="Console"/>--
>
<
appender-ref
ref=
"Console"
/
>
<appender-ref
ref=
"log"
/>
</root>
</loggers>
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论