类java.util.zip.ZipOutputStream源码实例Demo

下面列出了怎么用java.util.zip.ZipOutputStream的API类实例代码及写法,或者点击链接到github查看源代码。

源代码1 项目: submarine   文件: ZipUtilities.java
private static void addFileToZip(ZipOutputStream zos, File base, File file)
    throws IOException {
  byte[] buffer = new byte[1024];
  try (FileInputStream fis = new FileInputStream(file)) {
    String name = base.toURI().relativize(file.toURI()).getPath();
    LOG.info("Adding file {} to zip", name);
    zos.putNextEntry(new ZipEntry(name));
    int length;
    while ((length = fis.read(buffer)) > 0) {
      zos.write(buffer, 0, length);
    }
    zos.flush();
  } finally {
    zos.closeEntry();
  }
}
 
源代码2 项目: openapi-generator   文件: ZipUtil.java
/**
 * Compresses a collection of files to a destination zip file.
 * 
 * @param listFiles A collection of files and directories
 * @param destZipFile The path of the destination zip file
 * @throws FileNotFoundException if file not found
 * @throws IOException if IO exception occurs
 */
public void compressFiles(List<File> listFiles, String destZipFile)
        throws IOException {

    try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destZipFile))) {

        for (File file : listFiles) {
            if (file.isDirectory()) {
                addFolderToZip(file, file.getName(), zos);
            } else {
                addFileToZip(file, zos);
            }
        }

        zos.flush();
    }
}
 
源代码3 项目: brooklyn-server   文件: BundleMaker.java
private boolean addUrlItemRecursively(ZipOutputStream zout, String root, String item, Predicate<? super String> filter) throws IOException {
    InputStream itemFound = null;
    try {
        itemFound = resources.getResourceFromUrl(item);
    } catch (Exception e) {
        Exceptions.propagateIfFatal(e);
        return false;
    }
    try {
        // can't reliably tell if item a file or a folder (listing files), esp w classpath where folder is treated as a list of files, 
        // so if we can't tell try it as a list of files; not guaranteed, and empty dir and a file of size 0 will appear identical, but better than was
        // (mainly used for tests)
        if (isKnownNotToBeADirectoryListing(item) || !addUrlDirToZipRecursively(zout, root, item, itemFound, filter)) {
            addUrlFileToZip(zout, root, item, filter);
        }
        return true;
    } finally {
        Streams.closeQuietly(itemFound);
    }
}
 
源代码4 项目: sakai   文件: ZipContentUtil.java
/**
 * Iterates the collection.getMembers() and streams content resources recursively to the ZipOutputStream
 * 
 * @param rootId
 * @param collection
 * @param out
 * @throws Exception
 */
private void storeContentCollection(String rootId, ContentCollection collection, ZipOutputStream out) throws Exception {
	List<String> members = collection.getMembers();
	if (members.isEmpty()) storeEmptyFolder(rootId,collection,out);
	else {
		for (String memberId: members) {
			if (memberId.endsWith(Entity.SEPARATOR)) {
				ContentCollection memberCollection = ContentHostingService.getCollection(memberId);
				storeContentCollection(rootId,memberCollection,out);
			} 
			else {
				ContentResource resource = ContentHostingService.getResource(memberId);
				storeContentResource(rootId, resource, out);
			}
		}
	}
}
 
@Test
public void testLoadLoinc() throws Exception {
    ourLog.info("TEST = testLoadLoinc()");
    ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
    ZipOutputStream zos1 = new ZipOutputStream(bos1);
    addEntry(zos1, "/loinc/", "loinc.csv");
    zos1.close();
    ourLog.info("ZIP file has {} bytes", bos1.toByteArray().length);

    ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
    ZipOutputStream zos2 = new ZipOutputStream(bos2);
    addEntry(zos2, "/loinc/", "LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV");
    zos2.close();
    ourLog.info("ZIP file has {} bytes", bos2.toByteArray().length);

    RequestDetails details = mock(RequestDetails.class);
    when(codeSvc.findBySystem("http://loinc.org")).thenReturn(new CodeSystemEntity());
    mySvc.loadLoinc(list(bos1.toByteArray(), bos2.toByteArray()), details);

    verify(codeSvc).storeNewCodeSystemVersion( myCsvCaptor.capture(), any(RequestDetails.class));

    CodeSystemEntity ver = myCsvCaptor.getValue();
    ConceptEntity code = ver.getConcepts().iterator().next();
    assertEquals("10013-1", code.getCode());

}
 
源代码6 项目: TencentKona-8   文件: ClassFileInstaller.java
private static void writeJar(String jarFile, Manifest manifest, String classes[], int from, int to) throws Exception {
    if (DEBUG) {
        System.out.println("ClassFileInstaller: Writing to " + getJarPath(jarFile));
    }

    (new File(jarFile)).delete();
    FileOutputStream fos = new FileOutputStream(jarFile);
    ZipOutputStream zos = new ZipOutputStream(fos);

    // The manifest must be the first or second entry. See comments in JarInputStream
    // constructor and JDK-5046178.
    if (manifest != null) {
        writeToDisk(zos, "META-INF/MANIFEST.MF", manifest.getInputStream());
    }

    for (int i=from; i<to; i++) {
        writeClassToDisk(zos, classes[i]);
    }

    zos.close();
    fos.close();
}
 
源代码7 项目: carbon-apimgt   文件: ZIPUtils.java
/**
 * Creates a zip archive from the provided list of files
 *
 * @param zipFile absolute path to the zip file which needs to be created
 * @param fileList list of files
 * @throws APIManagementException when error occurred while creating the zip file
 */
public static void zipFiles(String zipFile, Collection<File> fileList) throws APIManagementException {
    byte[] buffer = new byte[1024];
    try (FileOutputStream fos = new FileOutputStream(zipFile);
         ZipOutputStream zos = new ZipOutputStream(fos)) {
        for (File file : fileList) {
            String path = file.getAbsolutePath().substring(
                    file.getAbsolutePath().indexOf(APIConstants.API_WSDL_EXTRACTED_DIRECTORY)
                            + APIConstants.API_WSDL_EXTRACTED_DIRECTORY.length() + 1);
            ZipEntry ze = new ZipEntry(path);
            zos.putNextEntry(ze);
            try (FileInputStream in = new FileInputStream(file)) {
                int len;
                while ((len = in.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
            }
        }
    } catch (IOException e) {
        throw new APIManagementException("Error occurred while creating the ZIP file: " + zipFile, e);
    }
}
 
源代码8 项目: zuihou-admin-cloud   文件: ZipUtils.java
/**
 * 通过流打包下载文件
 *
 * @param out
 * @param fileName
 * @param
 */
public static void zipFilesByInputStream(ZipOutputStream out, String fileName, InputStream is) throws Exception {
    byte[] buf = new byte[1024];
    try {
        out.putNextEntry(new ZipEntry(fileName));
        int len;
        while ((len = is.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        is.close();
    } catch (Exception e) {
        throw e;
    } finally {
        if (is != null) {
            is.close();
        }
    }
}
 
源代码9 项目: apicurio-studio   文件: OpenApi2JaxRs.java
/**
 * Generates a JaxRs project and streams the generated ZIP to the given
 * output stream.
 * @param output
 * @throws IOException
 */
public final void generate(OutputStream output) throws IOException {
    StringBuilder log = new StringBuilder();

    try (ZipOutputStream zos = new ZipOutputStream(output)) {
        try {
            CodegenInfo info = getInfoFromApiDoc();
            generateAll(info, log, zos);
        } catch (Exception e) {
            // If we get an error, put an PROJECT_GENERATION_ERROR file into the ZIP.
            zos.putNextEntry(new ZipEntry("PROJECT_GENERATION_FAILED.txt"));
            zos.write("An unexpected server error was encountered while generating the project.  See\r\n".getBytes());
            zos.write("the details of the error below.\r\n\r\n".getBytes());
            zos.write("Generation Log:\r\n\r\n".getBytes());
            zos.write(log.toString().getBytes(utf8));
            zos.write("\r\n\r\nServer Stack Trace:\r\n".getBytes());
            
            PrintWriter writer = new PrintWriter(zos);
            e.printStackTrace(writer);
            writer.flush();
            zos.closeEntry();
        }
    }
}
 
源代码10 项目: java-samples   文件: ZipDatasets.java
/**
 * Loop over each input dataset name (or pattern) given and
 * add entries for it to the Zip file.
 * If an exception occurs processing one entry, try to clean it
 * up and continue with the next entry. 
 * The {@link ZipDatasetSource} class does all of the real work.
 * <p/>
 * @param zipOutStream
 */
private void processInputFiles(ZipOutputStream zipOutStream) {
	for (int i=0; i<indsnames.length; i++) {
		String inputName = indsnames[i];
		ZipDatasetSource source = new ZipDatasetSource(inputName);
		try {
			source.addTo(zipOutStream, targetEncoding);
		} catch( Throwable t) {
			errors++;
			try { 
				zipOutStream.closeEntry(); 
			} catch (IOException ignore) {}
			System.out.println(">>> Error occuring processing input dataset: " + inputName);
			System.err.println(">>> Error occuring processing input dataset: " + inputName);
			t.printStackTrace();
		}
	}
}
 
源代码11 项目: datacollector   文件: SupportBundleManager.java
/**
 * Return InputStream from which a new generated resource bundle can be retrieved.
 */
public SupportBundle generateNewBundle(List<String> generatorNames, BundleType bundleType) throws IOException {
  List<BundleContentGeneratorDefinition> defs = getRequestedDefinitions(generatorNames);

  PipedInputStream inputStream = new PipedInputStream();
  PipedOutputStream outputStream = new PipedOutputStream();
  inputStream.connect(outputStream);
  ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);

  executor.submit(() -> generateNewBundleInternal(defs, bundleType, zipOutputStream));

  String bundleName = generateBundleName(bundleType);
  String bundleKey = generateBundleDate(bundleType) + "/" + bundleName;

  return new SupportBundle(
    bundleKey,
    bundleName,
    inputStream
  );
}
 
源代码12 项目: javacore   文件: ZipStreamDemo.java
/**
 * 压缩一个文件
 */
public static void output1(String filepath, String zipfilepath) throws Exception {
    // 1.使用 File 类绑定一个文件
    // 定义要压缩的文件
    File file = new File(filepath);
    // 定义压缩文件名称
    File zipFile = new File(zipfilepath);

    // 2.把 File 对象绑定到流对象上
    InputStream input = new FileInputStream(file);
    ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));

    // 3.进行读或写操作
    zipOut.putNextEntry(new ZipEntry(file.getName()));
    zipOut.setComment("This is a zip file.");
    int temp = 0;
    while ((temp = input.read()) != -1) { // 读取内容
        zipOut.write(temp); // 压缩输出
    }

    // 4.关闭流
    input.close();
    zipOut.close();
}
 
源代码13 项目: java-samples   文件: ZipDatasetSource.java
/**
 * Add an single {@link ZipEntry} for a single dataset or member.
 * 
 * @param zipOutStream the target ZipOutputStream
 * @param targetEncoding the target text encoding
 * @param ddname the DD allocated to the dataset or member
 * @param memberName the member name; used to create the entry name
 * @throws IOException
 */
private void addDatasetOrMember(ZipOutputStream zipOutStream, String targetEncoding, 
									String ddname, String memberName) throws IOException {

	Reader reader = null;
	try {	
		reader = openInputFile(ddname, memberName);
		// Construct the name of the Zip entry that we will add
		String entryName = memberName == null 
							? name
							: name + "/" + memberName;
		// Start a new ZipEntry in the Zip file,
		// copy the dataset/member data into the Zip entry,
		// and close the entry
		ZipEntry entry = new ZipEntry(entryName);
		zipOutStream.putNextEntry(entry);
		copyData(reader, zipOutStream, targetEncoding);
		zipOutStream.closeEntry();

		System.out.println("  added: " + entryName 
							+ "  (" + entry.getSize() + " -> " + entry.getCompressedSize() + ")");
	} finally {
		closeInputFile(reader);
		freeDD(ddname);
	}
}
 
源代码14 项目: ratel   文件: Androlib.java
public void buildUnknownFiles(File appDir, File outFile, MetaInfo meta)
        throws AndrolibException {
    if (meta.unknownFiles != null) {
        LOGGER.info("Copying unknown files/dir...");

        Map<String, String> files = meta.unknownFiles;
        File tempFile = new File(outFile.getParent(), outFile.getName() + ".apktool_temp");
        boolean renamed = outFile.renameTo(tempFile);
        if (!renamed) {
            throw new AndrolibException("Unable to rename temporary file");
        }

        try (
                ZipFile inputFile = new ZipFile(tempFile);
                ZipOutputStream actualOutput = new ZipOutputStream(new FileOutputStream(outFile))
        ) {
            copyExistingFiles(inputFile, actualOutput);
            copyUnknownFiles(appDir, actualOutput, files);
        } catch (IOException | BrutException ex) {
            throw new AndrolibException(ex);
        }

        // Remove our temporary file.
        tempFile.delete();
    }
}
 
源代码15 项目: ghidra   文件: ExtensionUtilsTest.java
/**
 * Create a generic zip that is a valid extension archive. 
 * 
 * @param zipName name of the zip to create
 * @return a zip file
 * @throws IOException if there's an error creating the zip
 */
private File createExtensionZip(String zipName) throws IOException {

	File f = new File(gLayout.getExtensionArchiveDir().getFile(false), zipName + ".zip");
	try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
		out.putNextEntry(new ZipEntry(zipName + "/"));
		out.putNextEntry(new ZipEntry(zipName + "/extension.properties"));

		StringBuilder sb = new StringBuilder();
		sb.append("name:" + zipName);
		byte[] data = sb.toString().getBytes();
		out.write(data, 0, data.length);
		out.closeEntry();
	}

	return f;
}
 
源代码16 项目: AndroidAPS   文件: MaintenancePlugin.java
public void zip(File zipFile, List<File> files) throws IOException {
    final int BUFFER_SIZE = 2048;

    ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));

    for (File file : files) {
        byte[] data = new byte[BUFFER_SIZE];

        try(FileInputStream fileInputStream = new FileInputStream( file )) {

            try(BufferedInputStream origin = new BufferedInputStream(fileInputStream, BUFFER_SIZE)) {
                ZipEntry entry = new ZipEntry(file.getName());

                out.putNextEntry(entry);
                int count;
                while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
                    out.write(data, 0, count);
                }

            }
        }
    }

    out.close();
}
 
源代码17 项目: buck   文件: ZipOutputStreamTest.java
@Test
public void shouldBeAbleToAddASingleNonZeroLengthFile() throws IOException {
  File reference = File.createTempFile("reference", ".zip");

  try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, mode);
      ZipOutputStream ref = new ZipOutputStream(new FileOutputStream(reference))) {
    byte[] bytes = "cheese".getBytes();
    ZipEntry entry = new ZipEntry("example.txt");
    entry.setTime(System.currentTimeMillis());
    out.putNextEntry(entry);
    ref.putNextEntry(entry);
    out.write(bytes);
    ref.write(bytes);
  }

  byte[] seen = Files.readAllBytes(output);
  byte[] expected = Files.readAllBytes(reference.toPath());

  assertArrayEquals(expected, seen);
}
 
源代码18 项目: geopaparazzi   文件: CompressionUtilities.java
static private void addFolderToZip(String path, String srcFolder, ZipOutputStream zip, String... excludeNames)
        throws IOException {
    if (isInArray(srcFolder, excludeNames)) {
        // jump folder if excluded
        return;
    }
    File folder = new File(srcFolder);
    String listOfFiles[] = folder.list();
    for (int i = 0; i < listOfFiles.length; i++) {
        if (isInArray(listOfFiles[i], excludeNames)) {
            // jump if excluded
            continue;
        }

        String folderPath = null;
        if (path.length() < 1) {
            folderPath = folder.getName();
        } else {
            folderPath = path + File.separator + folder.getName();
        }
        String srcFile = srcFolder + File.separator + listOfFiles[i];
        addToZip(folderPath, srcFile, zip, excludeNames);
    }
}
 
源代码19 项目: imsdk-android   文件: UnzipUtils.java
public static void zipFiles(Collection<File> resFileList, File zipFile, String comment, FeedBackServcie.Callback callback)
        throws IOException {
    final int BUFF_SIZE = 2048;
    ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(
            zipFile), BUFF_SIZE));
    int i = 0;
    for (File resFile : resFileList) {
        zipFile(resFile, zipout, "");
        if(callback != null){
            i++;
            callback.showFeedProgress(i,resFileList.size(), FeedBackServcie.FeedType.ZIP);
        }
    }
    zipout.setComment(comment);
    zipout.close();
}
 
源代码20 项目: tomee   文件: Archive.java
public File toJar(final String prefix, final String suffix) throws IOException {
    final File file = File.createTempFile(prefix, suffix);
    file.deleteOnExit();

    // Create the ZIP file
    final ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));

    for (final Map.Entry<String, byte[]> entry : entries().entrySet()) {
        out.putNextEntry(new ZipEntry(entry.getKey()));
        out.write(entry.getValue());
    }

    // Complete the ZIP file
    out.close();
    return file;
}
 
源代码21 项目: jmbe   文件: ZipUtility.java
/**
 * Compresses a list of files to a destination zip file
 *
 * @param listFiles A collection of files and directories
 * @param destZipFile The path of the destination zip file
 * @throws FileNotFoundException
 * @throws IOException
 */
public void zip(List<File> listFiles, String destZipFile) throws FileNotFoundException,
    IOException
{
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destZipFile));
    for(File file : listFiles)
    {
        if(file.isDirectory())
        {
            zipDirectory(file, file.getName(), zos);
        }
        else
        {
            zipFile(file, zos);
        }
    }
    zos.flush();
    zos.close();
}
 
源代码22 项目: flink   文件: FileUtils.java
public static Path compressDirectory(Path directory, Path target) throws IOException {
	FileSystem sourceFs = directory.getFileSystem();
	FileSystem targetFs = target.getFileSystem();

	try (ZipOutputStream out = new ZipOutputStream(targetFs.create(target, FileSystem.WriteMode.NO_OVERWRITE))) {
		addToZip(directory, sourceFs, directory.getParent(), out);
	}
	return target;
}
 
源代码23 项目: seezoon-framework-all   文件: GeneratorService.java
private byte[] zipCode(SysGen sysGen) throws IOException {
	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	ZipOutputStream zos = new ZipOutputStream(bos);
	for (String ftl : ftls) {
		String content = FreeMarkerUtils.renderTemplate(ftl, sysGen);
		logger.info("ftl {}:\r\n{}",ftl,content);
		zos.putNextEntry(new ZipEntry(this.getZipEntryName(ftl,sysGen)));
		IOUtils.write(content, zos);
		zos.closeEntry();
	}
	//这个地方有点反人类,按道理应该在取到byte[] 后关闭,测试,zos.flush 也无效,顾提前关闭,将流都刷入到数组中。
	zos.close();
	byte[] byteArray = bos.toByteArray();
	return byteArray;
}
 
源代码24 项目: spliceengine   文件: dbjarUtil.java
static void addEntries(ZipOutputStream zos, File dir, String dbName, int old) throws Exception {

		String[] list = dir.list();

		for (int i = 0; i < list.length; i++) {

			File f = new File(dir, list[i]);
			if (f.isDirectory()) {
				addEntries(zos, f, dbName, old);
			} else {
				addFile(zos, f, dbName, old);
			}

		}
	}
 
源代码25 项目: metanome-algorithms   文件: LongBitSet.java
public void compress(OutputStream out) throws IOException {
	ZipOutputStream zOut = new ZipOutputStream(out);
	// zOut.setLevel(Deflater.BEST_SPEED);
	zOut.putNextEntry(new ZipEntry("A"));
	DataOutputStream dOut = new DataOutputStream(zOut);
	dOut.writeInt(mUnits.length);
	for (int ii = 0; ii < mUnits.length; ii++) {
		dOut.writeLong(mUnits[ii]);
	}
	dOut.flush();
	zOut.closeEntry();
	zOut.flush();
}
 
源代码26 项目: openjdk-jdk9   文件: ClassFileInstaller.java
private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode, String prependPath) throws Exception {
    // Convert dotted class name to a path to a class file
    String pathName = className.replace('.', '/').concat(".class");
    if (prependPath.length() > 0) {
        pathName = prependPath + "/" + pathName;
    }
    writeToDisk(zos, pathName, new ByteArrayInputStream(bytecode));
}
 
源代码27 项目: spotbugs   文件: RejarClassesForAnalysis.java
public @Nonnull ZipOutputStream getZipOutputFile(String path) {
    ZipOutputStream result = analysisOutputFiles.get(path);
    if (result != null) {
        return result;
    }
    SortedMap<String, ZipOutputStream> head = analysisOutputFiles.headMap(path);
    String matchingPath = head.lastKey();
    result = analysisOutputFiles.get(matchingPath);
    if (result == null) {
        throw new IllegalArgumentException("No zip output file for " + path);
    }
    return result;
}
 
源代码28 项目: flink   文件: FileUtils.java
public static Path compressDirectory(Path directory, Path target) throws IOException {
	FileSystem sourceFs = directory.getFileSystem();
	FileSystem targetFs = target.getFileSystem();

	Path absolutePath = absolutizePath(directory);
	Path absoluteTargetPath = absolutizePath(target);
	try (ZipOutputStream out = new ZipOutputStream(targetFs.create(absoluteTargetPath, FileSystem.WriteMode.NO_OVERWRITE))) {
		addToZip(absolutePath, sourceFs, absolutePath.getParent(), out);
	}
	return target;
}
 
源代码29 项目: pentaho-kettle   文件: JsonInputTest.java
@Test
public void testZipFileInput() throws Exception {
  ByteArrayOutputStream err = new ByteArrayOutputStream();
  helper.redirectLog( err, LogLevel.ERROR );

  final String input = getBasicTestJson();
  try ( FileObject fileObj = KettleVFS.getFileObject( BASE_RAM_DIR + "test.zip" ) ) {
    fileObj.createFile();
    try ( OutputStream out = fileObj.getContent().getOutputStream() ) {
      try ( ZipOutputStream zipOut = new ZipOutputStream( out ) ) {
        ZipEntry jsonFile = new ZipEntry( "test.json" );
        zipOut.putNextEntry( jsonFile );
        zipOut.write( input.getBytes() );
        zipOut.closeEntry();
        zipOut.flush();
      }
    }
    JsonInputField price = new JsonInputField();
    price.setName( "price" );
    price.setType( ValueMetaInterface.TYPE_NUMBER );
    price.setPath( "$..book[*].price" );

    JsonInputMeta meta = createSimpleMeta( "in file", price );
    meta.setIsAFile( true );
    meta.setRemoveSourceField( true );
    JsonInput jsonInput = createJsonInput( "in file", meta, new Object[][] {
      new Object[] { "zip:" + BASE_RAM_DIR + "test.zip!/test.json" }
    } );
    RowComparatorListener rowComparator = new RowComparatorListener(
      new Object[] { 8.95d },
      new Object[] { 12.99d },
      new Object[] { 8.99d },
      new Object[] { 22.99d } );
    jsonInput.addRowListener( rowComparator );
    processRows( jsonInput, 5 );
    Assert.assertEquals( err.toString(), 0, jsonInput.getErrors() );
  } finally {
    deleteFiles();
  }
}
 
源代码30 项目: nopol   文件: Ziper.java
public Ziper(String zipFilename, Project project) {
	try {
		this.root = project.getBasePath();
		this.fos = new FileOutputStream(zipFilename);
		this.zos = new ZipOutputStream(fos);
	} catch (FileNotFoundException e) {
		throw new RuntimeException(e);
	}
}
 
 类所在包
 同包方法