java POI 读写 excel(项目实际需求)

本贴最后更新于 4207 天前,其中的信息可能已经时过境迁

这几天由于工作需要,需要做一个报表比对工具(找出两张报表的差异)。需求如下

1、做一个客户端工具,采用java,可以不用GUI(考虑到,我目前只懂j2ee相关的技术,其实这个需求用python(python版本)来做是最合适的,可是我目前不会,当然后面我会学习下这们语言)

2、两张报表的比队列需要灵活配置,通过配置文件来控制需要比对的列(可以是一列,可以是多列)

3、需要找出表A中有的一条数据,但是表B中没有的。或者表B中有的,表A中没有的。或者表A和表B同时都存在的一条数据,但是里面的某一些字段不一样。

4、两张报表的格式可能不一样,有可能为csv,xls,xlsx。两张报表的列数也是不固定的(这两张报表可以是任意的两张报表)

5、将比对结果再汇总到一张excel中(格式没有要求,我这里默认的是xls)

6、主键可能为复合主键,比对的报表,可能需要一次比对多组报表(由于这个需求,是今天才加上的,所以目前代码还处理这个问题,当然会很快加上)

思路一:

POI1-1

1、采用二维数组为主要的数据结构。因为,报表的列数不确定,所以不能构造对象,采用下标来控制每一列

2、将A表中的第一行的主键,然后搜索表B的主键,如果没搜到记下来,如果搜到了,比较所配置的列看是否相同,如果不同记下来,再反搜,表B中的主键来搜素表A,如果表B中有的,表A中没有的,记下来。

将记下来的数据重组,再导出excel。

效率:两张表都是30多列,52行,大概一秒左右比对完导出到excel中。

思路二

 POI1-2

1、主要采用了循环加map的方式,再比较是否有相等行的时候,直接用,表A的mapA.get(mapB.get("key"))如果数据不为空,说明在表A中有数据和表B匹配,这里的get有效的减少了一次循环。利用了map.get的方法速度更快。其他的。但是主要逻辑,还是如思路相同

接下来贴出,处理这个需求的主要代码。贴出代码的目的,主要是希望各位网友看到后,能够给指点一二,我这代码,肯定还需要优化,重构。或者说换思路。当然你有什么想法,通过评论,或者邮件告诉我。谢谢

ReadCSVExcel方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import au.com.bytecode.opencsv.CSVReader;

import com.qly.report.operate.facade.IReadExcel;

public class ReadCsvImpl implements IReadExcel{
static String qlyStringArr[][] = new String[1000][1000];
static String otherStringArr[][] = new String[1000][1000];
static Map<String,Integer > qlycontent = new HashMap<String,Integer >();
static Map<String,Integer > othercontent = new HashMap<String,Integer >();

@Override
public Map&lt;String, Object&gt; readExcel(String path, String flag) {
	CSVReader reader = null;
	// 取特定列放到集合
	try {
		InputStream ins = new FileInputStream(new File(path));
		InputStreamReader in = new InputStreamReader(ins, &quot;gbk&quot;);
		reader = new CSVReader(in);
		int len = reader.readNext().length;
		String nextline[];
		int counter = 0;
		// 将不同的来源的csv文件分别存放到不同的二维数组中
		if (&quot;qly&quot;.equals(flag)) {
			Map&lt;String, Object&gt; qlyMap = new HashMap&lt;String, Object&gt;();
			while ((nextline = reader.readNext()) != null) {
				for (int i = 0; i &lt; len; i++) {
					qlyStringArr[counter][i] = nextline[i];
				}
				counter++;
			}
			qlycontent.put(&quot;colNum&quot;, len);
			qlycontent.put(&quot;rowNum&quot;, counter);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return qlyMap;
		}

		if (&quot;other&quot;.equals(flag)) {
			Map&lt;String, Object&gt; otherMap = new HashMap&lt;String, Object&gt;();
			while ((nextline = reader.readNext()) != null) {
				for (int i = 0; i &lt; len; i++) {
					otherStringArr[counter][i] = nextline[i];
				}
				counter++;
			}
			othercontent.put(&quot;colNum&quot;, len);
			othercontent.put(&quot;rowNum&quot;, counter);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}

	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		try {
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	return null;
}

}

ReadXlsExcel 方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.qly.report.operate.facade.IReadExcel;
import com.qly.report.util.ReportUtil;

public class ReadXlsImpl implements IReadExcel{

public static HSSFWorkbook wb = null;
public static HSSFSheet hssfSheet =null;
public static HSSFRow hssfRow = null;
public static XSSFWorkbook xb = null;
public static XSSFSheet xssfSheet =null;
public static XSSFRow xssfRow =null;
public static String qlyStringArr[][] = new String[1000][1000];
public 	static String otherStringArr[][] = new String[1000][1000];
static Map&lt;String,Integer &gt; qlycontent = new HashMap&lt;String,Integer &gt;();
static Map&lt;String,Integer &gt; othercontent = new HashMap&lt;String,Integer &gt;();
@SuppressWarnings({ &quot;deprecation&quot; })
@Override
public Map&lt;String ,Object&gt; readExcel(String path, String flag) {
	int counter = 0;
	try {
		InputStream is = new FileInputStream(new File(path));

		wb = new HSSFWorkbook(is);
		hssfSheet = wb.getSheetAt(0);
		// 得到总行数
		int rowNum = hssfSheet.getLastRowNum();
		hssfRow = hssfSheet.getRow(1);

		int colNum = hssfRow.getPhysicalNumberOfCells();
		// 正文内容应该从第二行开始,第一行为表头内容
		if(&quot;qly&quot;.equals(flag)){
			Map&lt;String,Object&gt;qlyMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				hssfRow = hssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					qlyStringArr[i][counter] = get2003StringCellValue(
							hssfRow.getCell((short)counter)).trim();
					counter++;
				}
			}
			qlycontent.put(&quot;colNum&quot;, counter);
			qlycontent.put(&quot;rowNum&quot;, rowNum);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return  qlyMap;
		}
		if(&quot;other&quot;.equals(flag)){
			Map&lt;String,Object&gt;otherMap = new HashMap&lt;String, Object&gt;();
			for (int i =1; i &lt; rowNum; i++) {
				hssfRow = hssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					otherStringArr[i][counter] = get2003StringCellValue(hssfRow.getCell((short) counter)).trim();
					
					counter++;
				}
			}
			othercontent.put(&quot;colNum&quot;, counter);
			othercontent.put(&quot;rowNum&quot;, rowNum);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}


	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}	
	return null;
}
private static String get2003StringCellValue(HSSFCell cell) {
	String strCell = &quot;&quot;;
	
	if (null == cell) {
		return &quot;&quot;;
	}
	switch (cell.getCellType()) {
	case HSSFCell.CELL_TYPE_STRING:
		strCell = cell.getStringCellValue();
		break;
	case HSSFCell.CELL_TYPE_NUMERIC:
		//使用DecimalFormat类对科学计数法格式的数字进行格式化
		DecimalFormat df = new DecimalFormat(&quot;#&quot;);
		String str = String.valueOf(cell.getNumericCellValue());
		if(ReportUtil.isNumber(str)){
			strCell =  df.format(cell.getNumericCellValue());
		}else{
			strCell = str;
		}
		
		break;
	case HSSFCell.CELL_TYPE_BOOLEAN:
		
		strCell = String.valueOf(cell.getBooleanCellValue());
		break;
	case HSSFCell.CELL_TYPE_BLANK:
		strCell = &quot;&quot;;
		break;
	default:
		strCell = &quot;&quot;;
		break;
	}
	if (strCell.equals(&quot;&quot;) || null == strCell) {
		return &quot;&quot;;
	}
	return strCell;

}

}

ReadXlsxExcel方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.qly.report.operate.facade.IReadExcel;
import com.qly.report.util.ReportUtil;

public class ReadXlsxImpl implements IReadExcel {
public static HSSFWorkbook wb = null;
public static HSSFSheet hssfSheet =null;
public static HSSFRow hssfRow = null;
public static XSSFWorkbook xb = null;
public static XSSFSheet xssfSheet =null;
public static XSSFRow xssfRow =null;
public static String qlyStringArr[][] = new String[1000][1000];
public static String otherStringArr[][] = new String[1000][1000];
static Map<String,Integer > qlycontent = new HashMap<String,Integer >();
static Map<String,Integer > othercontent = new HashMap<String,Integer >();
@Override
public Map<String,Object> readExcel(String path, String flag) {
int counter = 0;
try {
InputStream is = new FileInputStream(new File(path));

		xb = new XSSFWorkbook(is);
		xssfSheet = xb.getSheetAt(0);
		// 得到总行数
		int rowNum = xssfSheet.getLastRowNum();
		xssfRow = xssfSheet.getRow(1);

		int colNum = xssfRow.getPhysicalNumberOfCells();
		// 正文内容应该从第二行开始,第一行为表头内容
		if(&quot;qly&quot;.equals(flag)){
			Map&lt;String,Object&gt;qlyMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				xssfRow = xssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					qlyStringArr[i][counter] = get2007StringCellValue(
							xssfRow.getCell((short) counter)).trim();
					counter++;
				}
			}
			qlycontent.put(&quot;colNum&quot;, counter);
			qlycontent.put(&quot;rowNum&quot;, rowNum);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return  qlyMap;
		}
		if(&quot;other&quot;.equals(flag)){
			Map&lt;String,Object&gt;otherMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				xssfRow = xssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					otherStringArr[i][counter] = get2007StringCellValue(
							xssfRow.getCell((short) counter)).trim();
					counter++;
				}
			}
			othercontent.put(&quot;colNum&quot;, counter);
			othercontent.put(&quot;rowNum&quot;, rowNum);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}
		
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
	return null;
}
private static String get2007StringCellValue(XSSFCell cell) {
	String strCell = &quot;&quot;;
	if (null == cell) {
		return &quot;&quot;;
	}
	switch (cell.getCellType()) {
	case XSSFCell.CELL_TYPE_STRING:
		strCell = cell.getStringCellValue();
		break;
	case XSSFCell.CELL_TYPE_NUMERIC:
		//使用DecimalFormat类对科学计数法格式的数字进行格式化
		
		DecimalFormat df = new DecimalFormat(&quot;#&quot;);
		String str = String.valueOf(cell.getNumericCellValue());
		if(ReportUtil.isNumber(str)){
			strCell =  df.format(cell.getNumericCellValue());
		}else{
			strCell = str;
		}
		
		break;
	case XSSFCell.CELL_TYPE_BOOLEAN:
		strCell = String.valueOf(cell.getBooleanCellValue());
		break;
	case XSSFCell.CELL_TYPE_BLANK:
		strCell = &quot;&quot;;
		break;
	default:
		strCell = &quot;&quot;;
		break;
	}
	if (strCell.equals(&quot;&quot;) || null == strCell) {
		return &quot;&quot;;
	}
	return strCell;

}

}

 

 

CompareExcel方法,比较算法在这里

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.qly.report.operate.facade.ICompareExcel;
import com.qly.report.util.ReportUtil;
/**

  • by guop 2013-7-12 上午 9:11:06

  • 比较 excel
    */
    public class CompareExcelImpl implements ICompareExcel{

    @Override
    public Map<String ,Object> compareExcel(String [][] qlyString, String [][] otherString,
    int[] qlycolumn, int[] othercolumn,
    Map<String,Integer> qlycontent, Map<String,Integer> othercontent,
    int qlyflag, int otherflag, int qlystartRow, int otherstartRow,
    String outReportPath) {

     // 761报表的行数
     int qlyRowNum = qlycontent.get(&quot;rowNum&quot;);
     // 761报表的列数
     int otherRowNum = othercontent.get(&quot;rowNum&quot;);
    
     List&lt;Map&lt;String, Integer&gt;&gt; listErrorStr = new ArrayList&lt;Map&lt;String, Integer&gt;&gt;();
     // 在这里比较下,用a表的标记字段扫描b表从1开始,0为表头
     for (int i = qlystartRow; i &lt; qlyRowNum; i++) {
     	boolean boolflag = false;
     	boolean boolother = true;
     	Map&lt;String, Integer&gt; errorMap = new HashMap&lt;String, Integer&gt;();
    
     	for (int j = otherstartRow; j &lt; otherRowNum; j++) {
     		// 按照配置的标记列,如761中的票号,和腾邦的票号
     		// 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0
     		if (ReportUtil.handleSpecialCharacter(qlyString[i][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[j][otherflag].trim()))) {
     			boolother = false;
     			int rowother = j;
     			// 在寻找到b表中,有相同的字段后,比较其他字段是否相同
     			for (int a1 = 0; a1 &lt; qlycolumn.length;a1++) {
     				if(null == qlyString[i][qlycolumn[a1]] || null == otherString[rowother][othercolumn[a1]]){
     					break;
     				}
    
     				// 当a表和b表中的 票面号相同,比较里面的规定的字段的值是否相同
     					if (!ReportUtil.handleSpecialCharacter(qlyString[i][qlycolumn[a1]].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[rowother][othercolumn[a1]].trim()))) {
     						errorMap.put(&quot;qlylinenumber&quot;, i);
     						errorMap.put(&quot;otherlinenumber&quot;, rowother);
     						listErrorStr.add(errorMap);
     						boolflag = true;
     						break;
     					} 
     				}
    
     			if (boolflag) {
     				break;
     			}
     		}
     	}
     	if (boolother) {
     		errorMap.put(&quot;qlylinenumber&quot;, i);
     		listErrorStr.add(errorMap);
     	}
     }
     //用b表扫描a表的某一个字段
     		// 在这里比较下,用a表的标记字段扫描b表
     for (int i = otherstartRow; i &lt; otherRowNum; i++) {
     	boolean boolother = true;
     	Map&lt;String, Integer&gt; errorMap = new HashMap&lt;String, Integer&gt;();
     	for (int j = qlystartRow; j &lt; qlyRowNum; j++) {
    
     		// 按照配置的标记列,如761中的票号,和腾邦的票号
     		// 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0
     		if (ReportUtil.handleSpecialCharacter(qlyString[j][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[i][otherflag].trim()))) {
     			boolother = false;
     			// 在寻找到b表中,有相同的字段后,比较其他字段是否相同
     		}
     	}
     	if (boolother) {
     		errorMap.put(&quot;otherlinenumber&quot;, i);
     		listErrorStr.add(errorMap);
     	}
     }
    
     Map&lt;String,Object&gt; compareMap = new HashMap&lt;String, Object&gt;();
     compareMap.put(&quot;listErrorStr&quot;, listErrorStr);
    

    return compareMap;
    }

}

全部代码在这里,github,请多多指教

  • POI
    23 引用 • 21 回帖
  • Excel
    31 引用 • 28 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3192 引用 • 8214 回帖 • 2 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone

    老船长这个不是专栏是博客吧。哈哈。专栏不是这个意思吧。

推荐标签 标签

  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 30 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖
  • OneDrive
    2 引用 • 3 关注
  • Excel
    31 引用 • 28 回帖
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    179 引用 • 407 回帖 • 485 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 753 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    170 引用 • 513 回帖
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 2 关注
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 2 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 207 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖 • 1 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 2 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 177 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 437 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    12 引用 • 54 回帖 • 30 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    211 引用 • 358 回帖
  • 印象笔记
    3 引用 • 16 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 600 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    179 引用 • 996 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 72 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 780 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖