shade.com.alibaba.fastjson2.support.csv.CSVWriter Maven / Gradle / Ivy
package com.alibaba.fastjson2.support.csv;
import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.util.*;
import com.alibaba.fastjson2.writer.FieldWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;
import com.alibaba.fastjson2.writer.ObjectWriterAdapter;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.function.IntFunction;
import static com.alibaba.fastjson2.util.DateUtils.DEFAULT_ZONE_ID;
public abstract class CSVWriter
implements Closeable, Flushable {
private long features;
final ZoneId zoneId;
int off;
CSVWriter(ZoneId zoneId, Feature... features) {
for (Feature feature : features) {
this.features |= feature.mask;
}
this.zoneId = zoneId;
}
public static CSVWriter of() {
return of(new ByteArrayOutputStream());
}
public static CSVWriter of(File file) throws FileNotFoundException {
return of(new FileOutputStream(file), StandardCharsets.UTF_8);
}
public static CSVWriter of(File file, Charset charset) throws FileNotFoundException {
return of(new FileOutputStream(file), charset);
}
public final void writeLineObject(Object object) {
if (object == null) {
this.writeLine();
return;
}
ObjectWriterProvider provider = JSONFactory.getDefaultObjectWriterProvider();
Class> objectClass = object.getClass();
ObjectWriter objectWriter = provider.getObjectWriter(objectClass);
if (objectWriter instanceof ObjectWriterAdapter) {
ObjectWriterAdapter adapter = (ObjectWriterAdapter) objectWriter;
List fieldWriters = adapter.getFieldWriters();
if (fieldWriters.size() == 1 && (fieldWriters.get(0).features & FieldInfo.VALUE_MASK) != 0) {
Object fieldValue = fieldWriters.get(0).getFieldValue(object);
writeLineObject(fieldValue);
return;
}
Object[] values = new Object[fieldWriters.size()];
for (int i = 0; i < fieldWriters.size(); i++) {
values[i] = fieldWriters.get(i).getFieldValue(object);
}
writeLine(values);
} else {
writeLine(object);
}
}
public final void writeDate(Date date) {
if (date == null) {
return;
}
long millis = date.getTime();
writeDate(millis);
}
public final void writeInstant(Instant instant) {
if (instant == null) {
return;
}
int nano = instant.getNano();
if (nano % 1000000 == 0) {
long millis = instant.toEpochMilli();
writeDate(millis);
return;
}
if ((features & Feature.AlwaysQuoteStrings.mask) != 0) {
writeQuote();
}
LocalDateTime ldt = instant.atZone(zoneId).toLocalDateTime();
writeLocalDateTime(ldt);
}
public void writeLocalDate(LocalDate date) {
if (date == null) {
return;
}
String str = DateTimeFormatter.ISO_LOCAL_DATE.format(date);
writeRaw(str);
}
public abstract void writeLocalDateTime(LocalDateTime instant);
// protected abstract void writeDirect(byte[] bytes, int off, int len);
public final void writeLine(int columnCount, IntFunction function) {
for (int i = 0; i < columnCount; i++) {
Object value = function.apply(i);
if (i != 0) {
writeComma();
}
writeValue(value);
}
writeLine();
}
public final void writeLine(List values) {
for (int i = 0; i < values.size(); i++) {
if (i != 0) {
writeComma();
}
writeValue(values.get(i));
}
writeLine();
}
public final void writeLine(Object... values) {
for (int i = 0; i < values.length; i++) {
if (i != 0) {
writeComma();
}
writeValue(values[i]);
}
writeLine();
}
public abstract void writeComma();
protected abstract void writeQuote();
public abstract void writeLine();
public void writeValue(Object value) {
if (value == null) {
return;
}
if (value instanceof Optional) {
Optional optional = (Optional) value;
if (!optional.isPresent()) {
return;
}
value = optional.get();
}
if (value instanceof Integer) {
this.writeInt32((Integer) value);
} else if (value instanceof Long) {
this.writeInt64((Long) value);
} else if (value instanceof String) {
writeString((String) value);
} else if (value instanceof Boolean) {
boolean booleanValue = (Boolean) value;
writeBoolean(booleanValue);
} else if (value instanceof Float) {
float floatValue = (Float) value;
writeFloat(floatValue);
} else if (value instanceof Double) {
writeDouble((Double) value);
} else if (value instanceof Short) {
this.writeInt32(((Short) value).intValue());
} else if (value instanceof Byte) {
this.writeInt32(((Byte) value).intValue());
} else if (value instanceof BigDecimal) {
writeDecimal((BigDecimal) value);
} else if (value instanceof BigInteger) {
writeBigInteger((BigInteger) value);
} else if (value instanceof Date) {
writeDate((Date) value);
} else if (value instanceof Instant) {
writeInstant((Instant) value);
} else if (value instanceof LocalDate) {
writeLocalDate((LocalDate) value);
} else if (value instanceof LocalDateTime) {
writeLocalDateTime((LocalDateTime) value);
} else {
String str = value.toString();
writeString(str);
}
}
public void writeBigInteger(BigInteger value) {
if (value == null) {
return;
}
String str = value.toString();
writeRaw(str);
}
public abstract void writeBoolean(boolean booleanValue);
public abstract void writeInt64(long longValue);
public final void writeDate(long millis) {
ZoneId zoneId = this.zoneId;
final int SECONDS_PER_DAY = 60 * 60 * 24;
long epochSecond = Math.floorDiv(millis, 1000L);
int offsetTotalSeconds;
if (zoneId == DateUtils.SHANGHAI_ZONE_ID || zoneId.getRules() == DateUtils.SHANGHAI_ZONE_RULES) {
offsetTotalSeconds = DateUtils.getShanghaiZoneOffsetTotalSeconds(epochSecond);
} else {
Instant instant = Instant.ofEpochMilli(millis);
offsetTotalSeconds = zoneId.getRules().getOffset(instant).getTotalSeconds();
}
long localSecond = epochSecond + offsetTotalSeconds;
long localEpochDay = Math.floorDiv(localSecond, (long) SECONDS_PER_DAY);
int secsOfDay = (int) Math.floorMod(localSecond, (long) SECONDS_PER_DAY);
int year, month, dayOfMonth;
{
final int DAYS_PER_CYCLE = 146097;
final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
long zeroDay = localEpochDay + DAYS_0000_TO_1970;
// find the march-based year
zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four-year cycle
long adjust = 0;
if (zeroDay < 0) {
// adjust negative years to positive for calculation
long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
adjust = adjustCycles * 400;
zeroDay += -adjustCycles * DAYS_PER_CYCLE;
}
long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
if (doyEst < 0) {
// fix estimate
yearEst--;
doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
}
yearEst += adjust; // reset any negative year
int marchDoy0 = (int) doyEst;
// convert march-based values back to january-based
int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
month = (marchMonth0 + 2) % 12 + 1;
dayOfMonth = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
yearEst += marchMonth0 / 10;
// check year now we are certain it is correct
if (yearEst < Year.MIN_VALUE || yearEst > Year.MAX_VALUE) {
throw new DateTimeException("Invalid year " + yearEst);
}
year = (int) yearEst;
}
int hour, minute, second;
{
final int MINUTES_PER_HOUR = 60;
final int SECONDS_PER_MINUTE = 60;
final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
long secondOfDay = secsOfDay;
if (secondOfDay < 0 || secondOfDay > 86399) {
throw new DateTimeException("Invalid secondOfDay " + secondOfDay);
}
int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
secondOfDay -= hours * SECONDS_PER_HOUR;
int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
secondOfDay -= minutes * SECONDS_PER_MINUTE;
hour = hours;
minute = minutes;
second = (int) secondOfDay;
}
if (year >= 0 && year <= 9999) {
int mos = (int) Math.floorMod(millis, 1000L);
if (mos == 0) {
if (hour == 0 && minute == 0 && second == 0) {
writeDateYYYMMDD10(year, month, dayOfMonth);
} else {
writeDateTime19(year, month, dayOfMonth, hour, minute, second);
}
return;
}
}
String str = DateUtils.toString(millis, false, zoneId);
writeRaw(str);
}
public abstract void writeDateYYYMMDD10(int year, int month, int dayOfMonth);
public abstract void writeDateTime19(
int year,
int month,
int dayOfMonth,
int hour,
int minute,
int second);
public abstract void writeString(String value);
public abstract void writeInt32(int intValue);
public abstract void writeDouble(double value);
public abstract void writeFloat(float value);
public abstract void flush();
public abstract void writeString(byte[] utf8);
public abstract void writeDecimal(BigDecimal value);
public abstract void writeDecimal(long unscaledVal, int scale);
protected abstract void writeRaw(String str);
@Override
public abstract void close() throws IOException;
public static CSVWriter of(OutputStream out, Feature... features) {
return new CSVWriterUTF8(out, StandardCharsets.UTF_8, DEFAULT_ZONE_ID, features);
}
public static CSVWriter of(OutputStream out, Charset charset) {
return of(out, charset, DEFAULT_ZONE_ID);
}
public static CSVWriter of(OutputStream out, Charset charset, ZoneId zoneId) {
if (charset == StandardCharsets.UTF_16
|| charset == StandardCharsets.UTF_16LE
|| charset == StandardCharsets.UTF_16BE
) {
return of(new OutputStreamWriter(out, charset), zoneId);
}
if (charset == null) {
charset = StandardCharsets.UTF_8;
}
return new CSVWriterUTF8(out, charset, zoneId);
}
public static CSVWriter of(Writer out) {
return new CSVWriterUTF16(out, DEFAULT_ZONE_ID);
}
public static CSVWriter of(Writer out, ZoneId zoneId) {
return new CSVWriterUTF16(out, zoneId);
}
public enum Feature {
AlwaysQuoteStrings(1);
public final long mask;
Feature(long mask) {
this.mask = mask;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy